浙江省一建建设集团网站,网站建设黄页视频,100个免费货源网站,广东省会计信息服务平台目录
低电平触发中断和下降沿触发中断的区别
红外遥控
Int0.c
Int.h
Timer0.c
Timer0.h
IR.c
IR.h
main.c
红外遥控电机调速
Timer1.c
Timer.h
Motor.c
Motor.h
main.c 上一节讲了红外发送和接收的工作原理#xff0c;这一节开始代码演示#xff01;
提前说…目录
低电平触发中断和下降沿触发中断的区别
红外遥控
Int0.c
Int.h
Timer0.c
Timer0.h
IR.c
IR.h
main.c
红外遥控电机调速
Timer1.c
Timer.h
Motor.c
Motor.h
main.c 上一节讲了红外发送和接收的工作原理这一节开始代码演示
提前说明本节代码演示中会涉及定时器和中断系统
如果不懂定时器和中断系统的话建议去看看我之前已经详细写过的中断系统和定时器的博客也写的比较全面的了看过后肯定能让你明白中断系统和定时器的工作原理
单片机学习笔记---中断系统含外部中断-CSDN博客
单片机学习笔记---定时器/计数器简述版_定时计数器ea-CSDN博客
单片机学习笔记---定时器和中断系统如何连起来工作-CSDN博客 低电平触发中断和下降沿触发中断的区别
在正式演示红外遥控的代码之前我们先来看看配置外部中断时选择低电平触发和下降沿触发有什么区别
我们用外部中断INT0来举个例子 我们单片机的原理图上INT0接的是单片机的P32口 而独立按键K3正好也是P32口。 那么我们按下K3的时候就相当于给单片机的P32口一个下降沿
那么我们现在来写一个程序验证一下选择低电平触发和下降沿触发有什么区别
先创建一个工程文件把我之前的博客中讲过的LCD1602的程序文件添加进来 然后在主程序main.c中调用这个函数来显示中断触发的现象
首先是选择下降沿触发
#include REGX52.H
#include LCD1602.hunsigned char Num;void main()
{LCD_Init();//初始化液晶屏//配置中断系统IT01;//选择下降沿触发方式IE00;//中断标志位清零EX01;//打开中断EA1;//打开总中断PX01;//一般都选择高优先级中断//跳转到中断函数//中断函数执行完进入while循环while(1){LCD_ShowNum(1,1,Num,3);}
}//中断函数
void Init0_Routine(void) interrupt 0
{Num;
}
下降沿触发的话你按下的时候加一次松开再按下的时候才再加一次。“松开状态再按下”这一个过程就是给一个下降沿的过程。
效果请看视频 选择下降沿触发中断的结果现象 再来看看选择低电平触发
#include REGX52.H
#include LCD1602.hunsigned char Num;void main()
{LCD_Init();//初始化液晶屏//配置中断系统IT00;//选择低电平触发方式IE00;//中断标志位清零EX01;//打开中断EA1;//打开总中断PX01;//一般都选择高优先级中断//跳转到中断函数//中断函数执行完进入while循环while(1){LCD_ShowNum(1,1,Num,3);}
}//中断函数
void Init0_Routine(void) interrupt 0
{Num;
}
而如果是低电平触发的话只要按键按下这个中断会一直处于触发状态当中断函数结束之后它会再次进入直到变成高电平为止。那它的现象就是按下不松的时候这个数值是一直加的直到松手数值才停止加。
效果请看视频 选择低电平触发中断的结果现象 以上就是低电平触发中断和下降沿触发中断的区别
而本节红外遥控的示例代码要用的是下降沿触发中断的这种方式
红外遥控
现在开始正式演示代码
新创建一个工程文件红外遥控
将我之前的博客讲过的程序模块直接添加进来 然后先创建Int0.cInt.hIR.cIR.h和main.c文件
开始代码讲解
首先写一个初始化中断系统的函数
Int0.c
#include REGX52.Hvoid Int0_Init(void)
{IT01;//选择下降沿触发中断IE00;//中断标志位清零EX01;//把中断打开EA1;//打开总中断PX01;//选择高优先级中断
}
声明一下这个函数
Int.h
#ifndef __INT0_H__
#define __INT0_H__void Int0_Init(void);#endifTimer0.c
接下来我们把Timer0.c文件的程序改造一下
将计时器初始化函数中的中断系统配置部分删掉将初值清零并且关闭计时
#include REGX52.H
//定时器0初始化
void Timer0_Init(void)
{TMOD 0xF0; //设置定时器模式TMOD | 0x01; //设置定时器模式TL0 0; //设置定时初值TH0 0; //设置定时初值TF0 0; //清除TF0标志TR0 0; //定时器0不计时
}
单独写一个给定时器0设置初值的函数
//定时器0设置计数器值
void Timer0_SetCounter(unsigned int Value)
{TH0Value/256;//取出高八位赋值给TH0TL0Value%256;//取出低八位赋值给TH0
}
//Value要设置的计数器值范围0~65535
定时器0设置好初值后再写一个获取定时器0当时的计数器值的函数 //定时器0获取计数器值范围0~65535
unsigned int Timer0_GetCounter(void)
{return (TH08)|TL0;//将TH0的8位数据左移8位然后和TL0的8位数据组合成16位数据作为返回值
}然后再写一个函数用来控制定时器的开始和结束
//定时器0启动停止控制
//Flag 启动停止标志
//在TMOD寄存器中的GATE位等于0的情况下TR0是定时器0在方式1的工作模式下的启停控制位
//1为启动0为停止void Timer0_Run(unsigned char Flag)
{TR0Flag;
}将这几个函数声明一下
Timer0.h
#ifndef __TIMER0_H__
#define __TIMER0_H__void Timer0_Init(void);
void Timer0_SetCounter(unsigned int Value);
unsigned int Timer0_GetCounter(void);
void Timer0_Run(unsigned char Flag);#endif接下来写一下红外解码的程序函数
IR.c
先定义好一些变量后面会用到
#include REGX52.H
#include Timer0.h
#include Int0.hunsigned int IR_Time;//上一次中断到此次中断的时间
unsigned char IR_State;//接收的状态unsigned char IR_Data[4];//数据4个字节32位
unsigned char IR_pData;//告知当前是在第几位每次进来pData告诉告知现在收到第几位了收满32位之后就结束了unsigned char IR_DataFlag;//收到连发帧标志位
unsigned char IR_RepeatFlag;//重发标志
unsigned char IR_Address;//存的是地址
unsigned char IR_Command;//存的是命令码就是遥控上的键码
然后写一个红外遥控初始化函数
void IR_Init(void)
{Timer0_Init();//初始化定时器0Int0_Init();//初始化外部中断0
}
红外遥控获取收到数据帧标志位 返回值是否收到数据帧1为收到0为未收到
unsigned char IR_GetDataFlag(void)
{if(IR_DataFlag){IR_DataFlag0;//将收到连发帧标志位置0方便下一次进行return 1;//代表已经收到了}return 0;//如果IR_DataFlag0直接return 0
}
红外遥控获取收到连发帧标志位 返回值是否收到连发帧1为收到0为未收到
unsigned char IR_GetRepeatFlag(void)
{if(IR_RepeatFlag){IR_RepeatFlag0;return 1;}return 0;
}
红外遥控获取收到的地址数据 返回值 收到的地址数据
unsigned char IR_GetAddress(void)
{return IR_Address;
}
红外遥控获取收到的命令数据 返回值收到的命令数据
unsigned char IR_GetCommand(void)
{return IR_Command;
}
外部中断0中断函数下降沿触发执行
这部分主要是根据这张图定义的函数 void Int0_Routine(void) interrupt 0
{//第一次进入中断函数时if(IR_State0) //状态0空闲状态{Timer0_SetCounter(0); //定时计数器清0Timer0_Run(1); //定时器启动IR_State1; //置状态为1}//下一次进入中断函数时else if(IR_State1) //状态1等待Start信号或Repeat信号{IR_TimeTimer0_GetCounter(); //获取上一次中断到此次中断的时间Timer0_SetCounter(0); //定时计数器清0方便下次计时//计数器每加1就是1微秒,1000us1ms//如果计时为13.5ms即13500us则接收到了Start信号判定值在12MHz晶振下为13500在11.0592MHz晶振下为12442//因为有一些误差所以有可能不是13500us整需允许波动的范围//13500-112502250允许波动的范围不能超过2250可以给上下500的范围上下500即1000的波动范围//所以给个上下500波动的范围即13500-500~13500500合理if(IR_Time13500-500 IR_Time13500500){IR_State2; //置状态为2下次再来中断就要开始解码数据}//如果计时为11.25ms则接收到了Repeat信号判定值在12MHz晶振下为11250在11.0592MHz晶振下为10368else if(IR_Time11250-500 IR_Time11250500){//如果接收到这个信号就说明一帧已经结束了后面就不用数据了IR_RepeatFlag1; //置收到连发帧标志位为1Timer0_Run(0); //定时器停止IR_State0; //置状态为0}else //接收出错{IR_State1; //置状态为1继续收Start信号或者repeat信号}}//以上情况执行完就接收完了起始信号//那再次进入中断函数来就要开始解码else if(IR_State2) //状态2接收数据{IR_TimeTimer0_GetCounter(); //获取上一次中断到此次中断的时间Timer0_SetCounter(0); //定时计数器清0方便下次计时//如果计时为1120us则接收到了数据0判定值在12MHz晶振下为1120在11.0592MHz晶振下为1032if(IR_Time1120-500 IR_Time1120500){//收到0之后就要把数据写进去IR_Data[IR_pData/8]~(0x01(IR_pData%8)); //数据对应位清0//假设pData的范围是0~7即一个字节长度//那么如果要将第一个字节的8位对应位清零//可以写成IR_Data[0]~(0x01IR_pData);//但是我们是要4个字节把pData定义为告知32位数据中的哪一位数据变化范围是0~31//要将pData的范围0~31拆成4个字节也就是4个数组元素一个字节8位//那么每8位就是一个数组元素所以左移的范围要限制在一个字节中//因此左移的范围要限制在0~7则IR_pData%8//4个数组元素范围是IR_Data[0]~IR_Data[3]则IR_pData/8//这样程序就可以自动跳到下一个元素的第0位IR_pData; //数据位置指针自增}//如果计时为2250us则接收到了数据1判定值在12MHz晶振下为2250在11.0592MHz晶振下为2074else if(IR_Time2250-500 IR_Time2250500){IR_Data[IR_pData/8]|(0x01(IR_pData%8)); //数据对应位置1IR_pData; //数据位置指针自增}else //接收出错{IR_pData0; //数据位置指针清0IR_State1; //置状态为1}//32位数据解码完成后开始验证if(IR_pData32) //如果接收到了32位数据{IR_pData0; //数据位置指针清0if((IR_Data[0]~IR_Data[1]) (IR_Data[2]~IR_Data[3])) //数据验证{IR_AddressIR_Data[0]; //转存数据IR_CommandIR_Data[2];IR_DataFlag1; //置收到连发帧标志位为1}Timer0_Run(0); //定时器停止IR_State0; //置状态为0}}
}IR.h
声明一下这些函数并且把键码重定义方便主程序调用不用每次都查找对应的键码 #ifndef __IR_H__
#define __IR_H__#define IR_POWER 0x45
#define IR_MODE 0x46
#define IR_MUTE 0x47
#define IR_START_STOP 0x44
#define IR_PREVIOUS 0x40
#define IR_NEXT 0x43
#define IR_EQ 0x07
#define IR_VOL_MINUS 0x15
#define IR_VOL_ADD 0x09
#define IR_0 0x16
#define IR_RPT 0x19
#define IR_USD 0x0D
#define IR_1 0x0C
#define IR_2 0x18
#define IR_3 0x5E
#define IR_4 0x08
#define IR_5 0x1C
#define IR_6 0x5A
#define IR_7 0x42
#define IR_8 0x52
#define IR_9 0x4Avoid IR_Init(void);
unsigned char IR_GetDataFlag(void);
unsigned char IR_GetRepeatFlag(void);
unsigned char IR_GetAddress(void);
unsigned char IR_GetCommand(void);#endifmain.c #include REGX52.H
#include Delay.h
#include LCD1602.h
#include IR.hunsigned char Num;
unsigned char Address;
unsigned char Command;void main()
{LCD_Init();LCD_ShowString(1,1,ADDR CMD NUM);LCD_ShowString(2,1,00 00 000);IR_Init();while(1){if(IR_GetDataFlag() || IR_GetRepeatFlag()) //如果收到数据帧或者收到连发帧{AddressIR_GetAddress(); //获取遥控器地址码CommandIR_GetCommand(); //获取遥控器命令码LCD_ShowHexNum(2,1,Address,2); //显示遥控器地址码LCD_ShowHexNum(2,7,Command,2); //显示遥控器命令码即键码if(CommandIR_VOL_MINUS) //如果遥控器VOL-按键按下{Num--; //Num自减}if(CommandIR_VOL_ADD) //如果遥控器VOL按键按下{Num; //Num自增}LCD_ShowNum(2,12,Num,3); //显示Num}}
}
效果请看视频 红外遥控显示键码值 注意如果程序没有出凑但是没有结果反应的话请查看一下自己的开发板的晶振到底是12MHz还是11.0592MHz这两种晶振的机器周期是不一样的要在IR.c文件中的程序对应修改要修改的地方在IR.c文件程序中已经给出了注释请认真查看并修改 红外遥控电机调速
新创建一个工程红外遥控电机调速
这个程序是建立在之前写的直流电机调速的那个程序的基础上改造的之前是用独立按键用控制电机的运转的速度这次改为用红外遥控来控制电机的运转速度。
复用到的程序
Delay函数 数码管 中断系统配置定时器0配置红外解码 Timer1.c
由于红外解码部分用了定时器0所以我们要加一个定时器1程序即将Timer0.c复制一份并且对应的地方改成定时器
#include REGX52.Hvoid Timer1_Init(void)
{TMOD 0x0F; //设置定时器模式TMOD | 0x10; //设置定时器模式TL1 0x9C; //设置定时初值TH1 0xFF; //设置定时初值TF1 0; //清除TF1标志TR1 1; //定时器1开始计时ET11;EA1;PT10;
}
Timer.h
#ifndef __TIMER1_H__
#define __TIMER1_H__void Timer1_Init(void);#endifMotor.c
写一个驱动电机的模块
#include REGX52.H
#include Timer1.h//引脚定义
sbit MotorP1^0;unsigned char Counter,Compare;//电机初始化
void Motor_Init(void)
{Timer1_Init();
}//电机设置速度
//Speed 要设置的速度范围0~100
void Motor_SetSpeed(unsigned char Speed)
{CompareSpeed;
}//定时器1中断函数
void Timer1_Routine() interrupt 3
{TL1 0x9C; //设置定时初值TH1 0xFF; //设置定时初值Counter;Counter%100; //计数值变化范围限制在0~99if(CounterCompare) //计数值小于比较值{Motor1; //输出1}else //计数值大于比较值{Motor0; //输出0}
}Motor.h
#ifndef __MOTOR_H__
#define __MOTOR_H__void Motor_Init(void);
void Motor_SetSpeed(unsigned char Speed);#endifmain.c
#include REGX52.H
#include Delay.h
#include Key.h
#include Nixie.h
#include Motor.h
#include IR.hunsigned char Command,Speed;void main()
{Motor_Init();//初始化电机定时器1初始化IR_Init();//红外遥控初始化定时器0和中断系统初始化while(1){if(IR_GetDataFlag()) //如果收到数据帧{CommandIR_GetCommand(); //获取遥控器命令码//将命令码/键码和遥控上的数字对应起来if(CommandIR_0){Speed0;} //根据遥控器命令码设置速度if(CommandIR_1){Speed1;}if(CommandIR_2){Speed2;}if(CommandIR_3){Speed3;}//Motor_SetSpeed相当于PWM输出中用到的比较值if(Speed0){Motor_SetSpeed(0);} //速度输出if(Speed1){Motor_SetSpeed(50);}if(Speed2){Motor_SetSpeed(75);}if(Speed3){Motor_SetSpeed(100);}}Nixie(1,Speed); //数码管显示速度}
} 效果请看视频 红外摇控调档速的小风扇 注意如果程序没有出凑但是没有结果反应的话请查看一下自己的开发板的晶振到底是12MHz还是11.0592MHz这两种晶振的机器周期是不一样的要在IR.c文件中的程序对应修改要修改的地方在IR.c文件程序中已经给出了注释请认真查看并修改 以上就是本篇的内容源码会放在评论区含12MHz和11.0592MHz两种源码如有问题可评论区留言