中断系统的设置,是为了让CPU能对外界紧急事件进行实时处理
中断的过程是,当中断请求源发出中断请求时,CPU响应中断后,CPU先暂停当时正在执行的主程序,转而去处理中断服务程序,处理完后继续原来的工作
微型机一般允许多个中断源,当几个中断源同时发出中断时,CPU先响应最高优先级的中断
中断嵌套:CPU在处理中断时,外界产生了更高优先级的中断,CPU暂停当前中断,处理了更高优先级的中断后,在回来处理之前的中断,具有中断嵌套功能的系统叫多级中断系统,不具有的叫单级中断系统
此52单片机一般有8个中断请求源,分别对应8个中断查询次序号(中断号),这些中断被硬件所调用,通过编写中断查询次序号的中断服务程序,就可以让CPU在响应中断时,执行具体的功能代码;4个外部中断INT0,INT1,INT2,INT3,3个定时器中断,定时器0中断,定时器1中断,定时器3中断,1个串口中断。
每一个中断源都可用软件独立地控制为允许中断或关闭中断,每一个中断源的中断优先级均可用软件设置
中断相关的寄存器有:中断请求标志寄存器TCON和SCON,中断允许寄存器IE,中断优先级寄存器IP
TCON寄存器中IE0和IE1位是外部中断请求0和1的中断请求标志位,IT0和IT1位用于选择外部中断请求是负跳变触发,还是电平触发,IT置0为电平触发,即当加到INT上的外部中断请求输入信号为低电平时,将IE位置1,发出中断,CPU介入后,硬件将IE置0
IE寄存器对中断的允许和禁止实现两级控制,可位寻址,总的中断开关位EA(IE^7),EA置0,所有中断都无效,EA置1,中断源是否运行还要由低位的中断请求允许控制位的状态决定,置1对应中断源中断允许,置0中断无效,其他位ET0到ET2控制定时器0到2的溢出中断,ES控制串口,EX0到EX1控制外部中断0到1
中断开关如图

IP寄存器用于配置中断请求源的优先级,不同位配置不同中断请求源
优先级相同的多个中断,CPU的响应次序按照中断查询次序号来响应,0为最先,7为最低
中断请求源顺序如图

#include "reg52.h"
sbit ledblue =P3^7;
sbit ledyellow =P3^6;
void delay1000(){
int cnt=0;
TR0=1;
while(1){
if(TF0==1){
cnt++;
TF0=0; //定时器0爆表不中断,那么手动将TF0位置0
TL0=0x00;
TH0=0xDC;
}
if(cnt==100)break;
}
TR0=0;
}
void ClockInit(){
TMOD&=0x00;
TMOD|=0x11;
TL0=0x00;
TH0=0xDC;
TL1=0x00;
TH1=0xDC;
}
void main(){
ledblue=1;
ledyellow=0;
ClockInit();
EA=1;
ET1=1;
TR1=1;
while(1){
ledblue=!ledblue;
delay1000();
}
}
void Lightyellow() interrupt 3 //定时器1每10ms爆表一次,爆表时TF1位置1,进入中断,TF1位自动置0,然后将cnt++,加到50次,即0.5s后,黄灯电平翻转
{ static int cnt=0;
cnt++;
TL1=0x00;
TH1=0xDC;
if(cnt==50){
ledyellow=!ledyellow;
cnt=0;
}
}
SG90舵机需要的控制信号与一般的电平信号不同,他需要的控制信号是PWM信号,即占空比不同的方波信号
舵机接线为红线VCC,黑线GND,黄线PWM信号接收
SG90舵机有两个规格,180°类型的360°类型,对应PWM波的控制情况如图

180°版本 占空比越高,转动的角度越大,但是转动角度有些误差,需要微调,高电平时间大概90°要1570us,180°要2570us,2720us为最大角度(略微大于180°),220us为最小角度(略微小于0°);超过2730us,先转动到最大角度,然后按超出量多少,转动速度就是多少的转动速度转动一小会,然后再快速转动回最大角度,如此循环,小于220us同理,

360°版本
0到2.5%占空比,维持最快顺时针转速不变;2.5%到7.5%占空比,占空比越高,顺时针转速越慢;7.5%完全暂停;7.5%到12.5%占空比,占空比越高,逆时针转速越快;12.5%占空比往上,维持最快逆时针转速不变
SG90舵机还分为数字电机和模拟电机,数字电机,给一次PWM信号就能转动,模拟电机需要在一段时间内持续给PWM信号才能转动
我们采用的是180类型的模拟信号SG90舵机
注意:一般信号周期是固定的,对于控制不同仪器,可能信号周期会有所变化;而对于相应信号周期占空比可以变化,用来控制程度
PWM是脉冲宽度调制,通过对一系列脉冲的宽度进行调制,通过调节占空比,等效出需要的模拟信号波形,相当于用调节高低电平的时间长度来等效模拟信号,PWM给出的信号仍然是数字的,简而言之,PWM是一种对模拟信号电平进行数字编码的方法,比如1s内给持续5v的电压信号,占空比60%,相当于是1s内给持续3v的电压信号,占空比20%,相当于1s内给持续1v的电压信号
PWM波有两个决定条件,一个是信号周期,另一个是占空比
信号周期:PWM波是由周期的占空比信号组成,信号周期就是一个占空比信号所占的时间长度
占空比:一个信号周期内,信号处于高电平状态的时间占整个周期的时间,比如方波的占空比就是50%
占空比不同,表示的模拟信号不同,输出的电压就不同,对应的舵机旋转角度就不同
PWM信号可以通过C52自带的硬件产生,也可以通过IO口软件模拟产生,精准度略差
PWM波的频率不能太高,一般50hz,即信号周期0.02s,信号周期用定时器来控制
频率高的话,周期就小,固定时间内接收到的信号数量就越多,频率低的话,周期就大,固定时间内接收到的信号数量就越少,但是固定时间内二者高低电平所占时间的比例是相同的,为占空比
占空比每提升2.5%,舵机就增加45°
在大于周期的一段时间内持续输出对应占空比的PWM波,电机就会转动相应角度
因为定时器的初值由TH位和TL位设置,所以TH位可以等于(65536-定时时长/机器周期)/256得出,
TL位可以等于(65536-定时时长/机器周期)%256得出
注意:取模运算不可以用浮点数
用定时器0来输出周期占空比的高电平,定时器1来输出剩下周期时间的低电平。在电平跳变点(当前即定时器爆表)进入中断程序,来配置下一个定时器
将PWM波分为一段时间的高电平,一段时间的低电平,不断重复,起初打开定时器1,爆表后,进入中断程序,在中断程序中,设定输出高电平和定时器0的定时初值后,打开定时器0,结束中断程序,这样就输出了对应时间的高电平,等定时器0爆表后,进入中断程序,在中断程序中又设置输出低电平和定时器1的定时初值,然后结束中断程序
进入中断后要及时关闭当前定时器,再打开下一个定时器,这样保持定时器0运行一段时间,定时器1运行一段时间
#include "reg52.h"
#include<intrins.h>
sbit ledb=P3^7;
sbit ledy=P3^6;
sbit sg90 =P1^6;
int flag=0;
void Delay2000() //@11.0592MHz
{
unsigned char i, j, k;
_nop_();
i = 15;
j = 2;
k = 235;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void ClockInit(){
TMOD&=0x00;
TMOD|=0x11;
TL0=0x66;
TH0=0xbd;
TH1=0xfa;
TL1=0x9a;
EA=1;
ET0=1;
ET1=1;
}
void do1() interrupt 1
{
TR0=0;
sg90=0;
ledy=0;
ledb=1;
if(flag==0){
//TL1=0xcd;
//TH1=0xb9;
TH1=(65536-19500/1.085)/256;
TL1=(int)(65536-19500/1.085)%256;
}
if(flag==1){
//TL1=0x66;
//TH1=0xbd;
TH1=(65536-18500/1.085)/256;
TL1=(int)(65536-18500/1.085)%256; //取模不能用浮点数,需要强转
}
TR1=1;
}
void do2() interrupt 3
{
TR1=0;
sg90=1;
ledy=1;
ledb=0;
if(flag==0){//360°sg90舵机 2.5%占空比顺时针全速转动
// TL0=0x33;
// TH0=0xfe;
TH0=(65536-500/1.085)/256;
TL0=(int)(65536-500/1.085)%256;
}
if(flag==1){ //360°sg90舵机 7.5%占空比停止转动
// TL0=0x9a;
// TH0=0xfa;
TH0=(65536-1500/1.085)/256;
TL0=(int)(65536-1500/1.085)%256;
}
TR0=1;
}
void main(){
ledy=1;
ledb=0;
ClockInit();
TR1=1;
while(1){
flag=!flag; //切换占空比
Delay2000();
}
}
由于占空比每提升2.5%,舵机就增加45°,如果以45度为转动单位,那么可以将一个周期20ms秒分成40等分,每等分占0.5ms,每等分输出高电平或低电平
用一个变量cnt记录次数,爆表一次cnt++,将定时器爆表前可计时的时长定为0.5ms,每次爆表前持续输出高电平或者低电平,总共输出40次,代表一个周期;cnt自加到40后,cnt置0,代表循环
每增加2.5%的占空比,40次中,输出高电平的次数就多一次
#include "reg52.h"
#include<intrins.h>
sbit sg90 =P1^6;
sbit ledb =P3^7;
sbit ledy =P3^6;
int cnt=0;
int jd;
void Delay2000() //@11.0592MHz
{
unsigned char i, j, k;
_nop_();
i = 15;
j = 2;
k = 235;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void ClockInit(){
TMOD&=0x00;
TMOD|=0x11;
// TL0=0xff;
// TH0=0xb7;
TL1=0x33;
TH1=0xfe;
EA=1;
// ET0=1;
ET1=1;
}
void main(){
Delay2000();
ClockInit();
TR1=1;
while(1){
jd=3;
cnt=0;
TL1=0x33;
TH1=0xfe;
ledb=0;
ledy=1;
Delay2000();
jd=4;
cnt=0;
TL1=0x33;
TH1=0xfe;
ledb=1;
ledy=0;
Delay2000();
}
}
void do2() interrupt 3
{
cnt++;
if(cnt<=jd)sg90=1;
else sg90=0;
TL1=0x33;
TH1=0xfe;
if(cnt==40){
cnt=0;
}
}
通过发送和接收超声波,利用时间和声音传播速度计算出障碍物与模块的距离,测距范围2cm到400cm,精度为3mm
TRIG引脚,给予至少10us的高电平,产生发波指令,经过一小段时间产生8个40khz的超声波方波并发送出去,发送时,ECHO引脚由低电平跳转到高电平,当超声波反弹回来被接收时,ECHO引脚又高电平跳转到低电平
计算时间,ECHO引脚进入高电平时,打开定时器,ECHO引脚跳转会低电平时,关闭定时器,通过定时器的差值计算出超声波传播的时间,距离等于时间*340/2,定时器一次可计时71106us,最大测距为1208cm,所以满足400cm的测距范围
#include "reg52.h"
sbit ledblue =P3^7;
sbit ledyellow =P3^6;
sbit Trig=P2^5;
sbit Echo=P2^6;
void Delay10us() //@11.0592MHz
{
unsigned char i;
i = 2;
while (--i);
}
void ClockInit(){
TMOD&=0xf0;
TMOD|=0x01;
TH0=0x00;
TH0=0x00;
}
void startHC(){
Trig=1;
Delay10us();
Trig=0;
}
void main(){
double dis=0;
double time=0;
ClockInit();
while(1){
startHC();
while(Echo==0);
TR0=1;
while(Echo==1);
TR0=0;
time=(TH0*256+TL0)*1.085;
dis=time*0.017;
if(dis<10)ledblue=0;
else ledblue=1;
TH0=0x00;
TL0=0x00;
}
}
1、测距控制垃圾桶开关盖
2、按键控制垃圾桶开关盖
3、振动控制垃圾桶开关盖
4、开关盖时蜂鸣器响应
1、垃圾桶开关盖需要舵机转动角度来支撑,舵机转动不同的角度需要不同占空比的PWM波,实现PWM波,则需要定时器0和定时器1分别产生相应时间的高低电平循环,需要用到定时器中断
2、振动控制开关盖,如果只是把振动产生的信号或到测距控制开关盖中,则有可能发生振动已经产生,信号也产生了,但是代码没有捕获到这个信号,当运行到判断部分时,振动信号已经消失了,所以需要用到外部中断,信号产生时同时发起外部中断,用一个变量记录下这个信号,下次运行到判断部分时,能检测到这个变量,则会控制开关盖
外部中断IT0如果置0表示低电平触发,对于模块发出信号为低电平时会发出中断;置1表示下降沿触发,对于模块发出信号与高电平脉冲有效,因为发出脉冲后会跳变回低电平,跳回时发出中断
#include "reg52.h"
#include<intrins.h>
sbit ledblue =P3^7;
sbit ledyellow =P3^6;
sbit Trig =P2^5;
sbit Echo =P2^6;
sbit sg90 =P1^6;
sbit key1 =P2^1;
sbit zd =P3^2; //振动
sbit beep =P2^4; //继电器开关,用于控制喇叭
int jd=0;
int jdbake=0;
int flag=1;
int soundflag=0;
int zd_mark=0;
void Delay2000ms() //@11.0592MHz
{
unsigned char i, j, k;
_nop_();
i = 15;
j = 2;
k = 235;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void Delay100ms() //@11.0592MHz
{
unsigned char i, j;
i = 180;
j = 73;
do
{
while (--j);
} while (--i);
}
void Delay10us() //@11.0592MHz
{
unsigned char i;
i = 2;
while (--i);
}
void startHC(){
Trig=1;
Delay10us();
Trig=0;
}
double getDis(){
double time=0;
TH2=0x00;
TL2=0x00;
startHC();
while(Echo==0);
TR2=1;
while(Echo==1);
TR2=0;
time=(TH2*256+TL2)*1.085;
return (time*0.017);
}
void ClockInit(){
TMOD&=0x00;
TMOD|=0x11;
EA=1;
ET0=1;
ET1=1;
TR1=1;
}
void Sound(){
int i=0;
beep=0;
for(i;i<3;i++){
Delay100ms();
}
beep=1;
i=0;
for(i;i<3;i++){
Delay100ms();
}
}
void Clock2Init(){
TH2=0x00;
TL2=0x00;
}
void EX0Init(){
EX0=1;//开启外部中断
IT0=0;//中断触发为低电平
}
void main(){
double dis=0;
Clock2Init();
ClockInit();
EX0Init();
while(1){
dis=getDis();
if(key1==0){
Delay100ms();
flag=!flag;
if(soundflag==0){
soundflag=0;
}else {
soundflag=!soundflag;
}
}
if(flag==1){
EX0=1;
ledyellow=1;
if(dis<10||zd_mark==1){
EX0=0;
jd=180;
ledblue=0;
if(jdbake!=jd){
Sound();
}
jdbake=jd;
Delay2000ms();
zd_mark=0;
EX0=1;
}
else {
jd=0;
jdbake=jd;
ledblue=1;
Delay100ms();
}
}else{
EX0=0;
jd=180;
if(soundflag==0){
Sound(); //按键后只响一声
}
soundflag=1;
Delay100ms();
ledyellow=0;
}
}
}
void Low() interrupt 1
{
TR0=0;
sg90=0;
if(jd==0){
// TL1=0xcd;
// TH1=0xb9;
TH1=(65536-(20000-500)/1.085)/256;
TL1=(int)(65536-(20000-500)/1.085)%256;
}
if(jd==180){
//TL1=0x66;
//TH1=0xbd;
TH1=(65536-(20000-2570)/1.085)/256;
TL1=(int)(65536-(20000-2570)/1.085)%256; //¼Çסȡģ²»¿ÉÒÔÓø¡µãÊý
}
TR1=1;
}
void High() interrupt 3
{
TR1=0;
sg90=1;
if(jd==0){//ת¶¯
// TL0=0x33;
// TH0=0xfe;
TH0=(65536-500/1.085)/256; //1570 90° 210最小度数
TL0=(int)(65536-500/1.085)%256;
}
if(jd==180){ //ÔÝÍ£
// TL0=0x9a;
// TH0=0xfa;
TH0=(65536-2570/1.085)/256; //2570 180° 2720最大度数
TL0=(int)(65536-2570/1.085)%256;
}
TR0=1;
}
void get_zdsignal() interrupt 0
{
zd_mark=1;
}
说在前面这部分我本来是合为一篇来写的,因为目的是一样的,都是通过独立按键来控制LED闪灭本质上是起到开关的作用,即调用函数和中断函数。但是写一篇太累了,我还是决定分为两篇写,这篇是调用函数篇。在本篇中你主要看到这些东西!!!1.调用函数的方法(主要讲语法和格式)2.独立按键如何控制LED亮灭3.程序中的一些细节(软件消抖等)1.调用函数的方法思路还是比较清晰地,就是通过按下按键来控制LED闪灭,即每按下一次,LED取反一次。重要的是,把按键与LED联系在一起。我打算用K1来作为开关,看了一下开发板原理图,K1连接的是单片机的P31口,当按下K1时,P31是与GND相连的,也就是说,当我按下去时
在添加一些空格以使代码更具可读性时(与上面的代码对齐),我遇到了这个:classCdefx42endendm=C.new现在这将给出“错误数量的参数”:m.x*m.x这将给出“语法错误,意外的tSTAR,期待$end”:2/m.x*m.x这里的解析器到底发生了什么?我使用Ruby1.9.2和2.1.5进行了测试。 最佳答案 *用于运算符(42*42)和参数解包(myfun*[42,42])。当你这样做时:m.x*m.x2/m.x*m.xRuby将此解释为参数解包,而不是*运算符(即乘法)。如果您不熟悉它,参数解包(有时也称为“spl
require'mechanize'agent=Mechanize.newlogin=agent.get('http://www.schoolnet.ch/DE/HomeDE.htm')agent.clicklogin.link_withtext:/Login/然后我得到Mechanize::UnsupportedSchemeError。 最佳答案 Mechanize不支持javascript但您可以将搜索字段添加到表单并为其分配搜索词并使用mechanize提交表单form=page.forms.firstform.add_fie
在几个项目中,我希望有一个类似rakeserver的rake任务,它将通过任何需要的方式开始为该应用程序提供服务。这是一个示例:task:serverdo%x{bundleexecrackup-p1234}end这行得通,但是当我准备停止它时,按Ctrl+c并没有正常关闭;它中断了Rake任务本身,它说rakeaborted!并给出堆栈跟踪。在某些情况下,我必须执行Ctrl+c两次。我可能可以用Signal.trap写一些东西来更优雅地中断它。有没有更简单的方法? 最佳答案 trap('SIGINT'){puts"Yourmessa
我有可变数量的表格和可变数量的行,我想让它们一个接一个地显示,但如果表格不适合当前页面,请将其放在下一页,然后继续。我已将表格放入事务中,以便我可以回滚然后打印它(如果高度适合当前页面),但我如何获得表格高度?我现在有这段代码pdf.transactiondopdf.table@data,:font_size=>12,:border_style=>:grid,:horizontal_padding=>10,:vertical_padding=>3,:border_width=>2,:position=>:left,:row_colors=>["FFFFFF","DDDDDD"]pdf.
本人是音乐爱好者,从小就特别喜欢那个随着音乐跳动的方框效果,就是这个:arduino上一大把对,我忍你很久了,我就想用mpy做,全网没有,行我自己研究。果然兴趣是最好的老师,我之前有篇博客专门讲音频,有兴趣的可以回顾一下。提到可视化频谱,必然绕不开fft,大学学过这玩意,当时一心玩,老师讲的一个字都么听进去,网上教程简略扫了一下,大该就是把时域转频域的工具,我大mpy居然没有fft函数,奶奶的,先放着。音频信息如何收集?第一种傻瓜式的ADC,模拟转数字,原始粗暴,第二种,I2S库,我之前博客有讲过,数据是PCM编码。然后又去学PCM编码,一学豁然开朗,舒服,以代码为例:audio_in=I2S
我下面有一个ruby脚本,它无限地打印从1开始的数字。如何通过终端中的中断(如“Ctrl+C”或键“q”)使脚本停止无限执行?a=0while(a)putsaa+=1#thecodeshouldquitifaninterruptofacharacterisgivenend在每次迭代中,不应询问用户输入。 最佳答案 使用Kernel.trap为Ctrl-C安装信号处理程序:#!/usr/bin/rubyexit_requested=falseKernel.trap("INT"){exit_requested=true}while!
目录SPI总线SPI总线概述 SPI总线分类SPI优点及缺点SPI接口硬件原理SPI四种工作模式 74HC595应用74HC595芯片概述74HC595封装及管脚功能74HC595工作原理 编辑 74HC595串行转并行点亮LED灯 程序实现 Proteus运行结构示意图SPI总线SPI总线概述 SPI(SerialPeripheralinterface):串行外围设备接口 用途:用来在微控制器与外围设备芯片之间实现数据交换 特点:高速、全双工、同步 SPI总线分类四线制全双工SPI(同时收发)MISO 主机输入/从机输出MOSI 主机输出/从机输入SCLK 串行时钟CS或
文章目录1简介2绪论2.1课题背景与目的3系统设计详细设计描述3.2硬件部分温度测量电路其他电路部分3.3软件部分主程序子系统程序温湿度程序流程键盘显示子程序3.4实现效果3.5部分相关代码4最后1简介Hi,大家好,这里是丹成学长,今天向大家介绍一个单片机项目基于单片机的智能温控农业大棚系统大家可用于课程设计或毕业设计单片机-嵌入式毕设选题大全及项目分享:https://blog.csdn.net/m0_71572576/article/details/1254090522绪论2.1课题背景与目的近年来我国的温室控制取得了长足的进步,首先在温室群控制方面,进行了初步的探索和理论研究,其次在温室
一、概述在之前的一篇博文中,记录了AT24C01、AT24C02芯片的读写驱动,先将之前的相关文章include一下:1.IIC驱动:4位数码管显示模块TM1637芯片C语言驱动程序2.AT24C01/AT24C02读写:AT24C01/AT24C02系列EEPROM芯片单片机读写驱动程序本文记录分享AT24C04、AT24C08、AT24C16芯片的单片机C语言读写驱动程序。二、芯片对比介绍型号容量bit容量byte页数字节/页器件寻址位可寻址器件数WordAddress位数/字节数备注AT24C044k5123216A2A149/1WordAddress使用P0位AT24C088k1024