赞
踩
单片机,英文Micro Controller Unit,简称MCU 。内部集成了中央处理器CPU、随机存储器ROM、只读存储器RAM、定时器/计算器、中断系统和IO口等一系列电脑的常用硬件功能 单片机的任务是信息采集(依靠传感器)、处理(依靠CPU)和硬件设备(例如电机,LED等)的控制 。单片机跟计算机相比,单片机算是一个袖珍版计算机,一个芯片就能构成完整的计算机系统。但在性能上,与计算机相差甚远,但单片机成本低、体积小、结构简单,在生活和工业控制领域大有所用。 同时,学习使用单片机是了解计算机原理与结构的最佳选择。
单片机工作的基本时序
我们都知道在学校是通过铃声来控制所有班级的上下课时间,我们都知道单片机执行指令的过程就是从ROM取出一条指令执行来完成它在各个地方的作用,那它什么时候取指令这个是顺序呢?这里引入一个时序的周期,每访问一次ROM的时间,就是一个机器周期的时间。
1个机器周期 = 6个状态周期 = 12个时钟(振荡)周期
时钟周期:即单片机的基本时间单位,若晶体的频率=12MHZ,那时钟周期 = 1/12MHZ,一个时钟周期 = 1/12MHZ = 1/12000 000每秒
机器周期:即12x1/12 000 000 =0.000001s = 1us,访问一次ROM取指令的时间就是1us
重点需记:单片机管脚
1.电源:Vcc:正极 Gnd:负极 2.XTAL:单片机时钟引脚,外接晶振
3.RST:复位
- #include <REGX52.H>
- void main()
- {
- P2=0x7f;//1111 1110 d1 16 15
- //0111 1111 d8 7 16
- //1011 1111 d7 11 16
-
-
- }
通过高低电平控制led亮否
- #include <REGX52.H>
- #include <INTRINS.H>
-
- //延时函数
- void Delay500ms() //@11.0592MHz
- {
- unsigned char i, j, k;
-
- _nop_();
- i = 4;
- j = 129;
- k = 119;
- do
- {
- do
- {
- while (--k);
- } while (--j);
- } while (--i);
- }
-
- void main()
- {
- while(1){
- P2=0xfe;//亮
- Delay500ms();//延时500ms
- P2=0xff;//灭
- Delay500ms();//延时500ms
- }
- }
通过延时函数使led闪烁
- #include <REGX52.H>
- #include <INTRINS.H>
-
- void Delay500ms() //@11.0592MHz
- {
- unsigned char i, j, k;
-
- _nop_();
- i = 4;
- j = 129;
- k = 119;
- do
- {
- do
- {
- while (--k);
- } while (--j);
- } while (--i);
- }
-
- void main()
- {
- while(1){
- P2=0xfe;//1111 1110
- Delay500ms();
- P2=0xfd;//1111 1101
- Delay500ms();
- P2=0xfb;//1111 1011
- Delay500ms();
- P2=0xf7;//1111 0111
- Delay500ms();
- P2=0xef;//1110 1111
- Delay500ms();
- P2=0xdf;//1101 1111
- Delay500ms();
- P2=0xbf;//1011 1111
- Delay500ms();
- P2=0x7f;//0111 1111
- Delay500ms();
- }
- }
位运算做法:
- #include <REGX52.H>
- #include <INTRINS.H>
-
- //任意延时函数——1ms的延时函数执行x次循环
- void Delay1ms(unsigned int xms) //@11.0592MHz
- {
- unsigned char i, j;
- while(xms)
- {
- _nop_();
- i = 2;
- j = 199;
- do
- {
- while (--j);
- } while (--i);
-
- xms--;}
- }
-
- void main()
- {
- while(1){
- P2=0xfe;//1111 1110
- Delay1ms(100);
- P2=0xfd;//1111 1101
- Delay1ms(100);
- P2=0xfb;//1111 1011
- Delay1ms(100);
- P2=0xf7;//1111 0111
- Delay1ms(100);
- P2=0xef;//1110 1111
- Delay1ms(100);
- P2=0xdf;//1101 1111
- Delay1ms(100);
- P2=0xbf;//1011 1111
- Delay1ms(100);
- P2=0x7f;//0111 1111
- Delay1ms(100);
- }
- }
通过任意延时函数去简化步骤
- #include <REGX52.H>
-
- void main()
- {
- while(1)
- {
- if(P3_1==0)//低电平 按下按键接地为0
- {
- P2_0=0;//d1亮
- }
- else {
- P2_0=1;
- }
- }
- }
- #include <REGX52.H>
- #include <INTRINS.H>
- void Delay(unsigned int xms) //@11.0592MHz
- {
- unsigned char i, j;
- while(xms){
- _nop_();
- i = 2;
- j = 199;
- do
- {
- while (--j);
- } while (--i);
- xms--;
- }
- }
-
- void main()
- {
- while(1)
- {
- if(P3_1==0)
- {
- Delay(20);//取消前摇
- while(P3_1==0);//判断何时松手
- Delay(20);//取消后摇
-
- P2_0=~P2_0;//按位取反
- }
- }
- }
取消按键时的抖动,使单片机稳定判断状态。按一次亮,按一次灭。
- #include <REGX52.H>
- #include <INTRINS.H>
-
- void Delay(unsigned int xms) //@11.0592MHz
- {
- unsigned char i, j;
- while(xms){
- _nop_();
- i = 2;
- j = 199;
- do
- {
- while (--j);
- } while (--i);
- xms--;
- }
- }
-
- void main()
- {
- unsigned int lednum=0;
- while(1)
- {
- if(P3_1==0)
- {
- Delay(20);
- while(P3_1==0);
- Delay(20);
-
- lednum++;
- P2=~lednum;
- }
- }
- }
也可以直接用P2--;代替最后两句,完成二进制运算。
- #include <REGX52.H>
- #include <INTRINS.H>
-
- void Delay(unsigned int xms) //@11.0592MHz
- {
- unsigned char i, j;
- while(xms){
- _nop_();
- i = 2;
- j = 199;
- do
- {
- while (--j);
- } while (--i);
- xms--;
- }
- }
-
- void main()
- {
- unsigned int lednum=0;
- P2=~0x01;
- while(1)
- {
- if(P3_1==0)//k1
- {
- Delay(20);
- while(P3_1==0);
- Delay(20);
-
- lednum++;
- if(lednum>=8)
- lednum=0;
- P2=~(0x01<<lednum);
- }
- if(P3_0==0)//k2
- {
- Delay(20);
- while(P3_0==0);
- Delay(20);
-
-
- if(lednum==0)
- lednum=7;
- else lednum--;
- P2=~(0x01<<lednum);
- }
- }
- }
通过CBA给数字0和1二进制转换10进制(得到数字几)就控制Y几,Y0头上“—”是表示低电平有效(即给0):
CC2电容作用:滤波电容,稳定电源,确定电路稳定性,提高电路工作性能可靠运行;
RP4:排阻,限流,防止电流过大
只有Y5为0,其他Y0...Y7都为1;
读取顺序都是从下到上
二进制101转换为1十进制为5,控制Y5,即公共端的LED6;
要显示下图的数字6
代码实现如下(P2控制共阴极,P0控制显示数字)及结果;
- #include <REGX52.H>
- #include <INTRINS.H>
-
- unsigned char NixieTable[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x00};
-
- void Nixie(unsigned char Location,Number)
- {
- switch(Location)
- {
- case 1:P2_4=1;P2_3=1;P2_2=1;break;
- case 2:P2_4=1;P2_3=1;P2_2=0;break;
- case 3:P2_4=1;P2_3=0;P2_2=1;break;
- case 4:P2_4=1;P2_3=0;P2_2=0;break;
- case 5:P2_4=0;P2_3=1;P2_2=1;break;
- case 6:P2_4=0;P2_3=1;P2_2=0;break;
- case 7:P2_4=0;P2_3=0;P2_2=1;break;
- case 8:P2_4=0;P2_3=0;P2_2=0;break;
- }
- P0=NixieTable[Number];
- }
-
- void main()
- {
- Nixie(7,10);
- while(1);
- }
要显示的数字对应的值
- #include <REGX52.H>
- #include <INTRINS.H>
-
- unsigned char NixieTable[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x00};
-
- void Delay (unsigned int xms) //@11.0592MHz
- {
- unsigned char i, j;
- while(xms--){
- _nop_();
- i = 2;
- j = 199;
- do
- {
- while (--j);
- } while (--i);
- }
- }
-
- void Nixie(unsigned char Location,Number)
- {
- switch(Location)
- {
- case 1:P2_4=1;P2_3=1;P2_2=1;break;
- case 2:P2_4=1;P2_3=1;P2_2=0;break;
- case 3:P2_4=1;P2_3=0;P2_2=1;break;
- case 4:P2_4=1;P2_3=0;P2_2=0;break;
- case 5:P2_4=0;P2_3=1;P2_2=1;break;
- case 6:P2_4=0;P2_3=1;P2_2=0;break;
- case 7:P2_4=0;P2_3=0;P2_2=1;break;
- case 8:P2_4=0;P2_3=0;P2_2=0;break;
- }
- P0=NixieTable[Number];
- Delay(1);//保证亮度
- P0=0x00;//清零
- }
-
- void main()
- {
- while(1){
- Nixie(2,1);
- // Delay(20);
- Nixie(3,2);
- // Delay(20);
- Nixie(4,3);
- // Delay(20);
- }
- }
注释掉上面的延时调用,旁边的管会有些影响,需要消影,段选、位选影响造成串位,如下代码消除;
了解
- #include <REGX52.H>
- #include "LCD1602.h"
- #include "Delay.h"
-
- int Result=0;
-
- void main()
- {
- LCD_Init();//初始化
-
- while(1)
- {
- Result++;
- Delay(1000);
- LCD_ShowNum(1,1,Result,3);
- }//计时器
P14-P17给0就代表扫描,其他给1(没选中),一次只能扫描一行;P10-P13给0表示按下,给1表示没按下;(逐列扫描)
- #include <REGX52.H>
- #include "Delay.h"
-
- unsigned char MatrixKey()
- {
- unsigned char KeyNumber=0;
-
- P1=0xff; //按列扫描
- P1_3=0; //控制扫描的列
- if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);KeyNumber=1;} //while判断何时松手
- if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);KeyNumber=5;}
- if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=9;}
- if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=13;}
-
- P1=0xff;
- P1_2=0;
- if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);KeyNumber=2;}
- if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);KeyNumber=6;}
- if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=10;}
- if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=14;}
-
- P1=0xff;
- P1_1=0;
- if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);KeyNumber=3;}
- if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);KeyNumber=7;}
- if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=11;}
- if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=15;}
-
- P1=0xff;
- P1_0=0;
- if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);KeyNumber=4;}
- if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);KeyNumber=8;}
- if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=12;}
- if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=16;}
-
-
- return KeyNumber;
- }
- #include <REGX52.H>
- #include "Delay.h"
- #include "LCD1602.h"
- #include "matrixKey.h"
-
- unsigned char KeyNum;
-
- void main()
- {
- LCD_Init(); //LCD上电初始化
- LCD_ShowString(1,1,"Helloworld");
- while(1)
- {
- KeyNum=MatrixKey();
- if(KeyNum){
- LCD_ShowNum(2,1,KeyNum,2);
- }
- }
- }
快速生成常用格式代码:
设置,完成后双击就可以生成了:
- #include <REGX52.H>
- #include "Delay.h"
- #include "LCD1602.h"
- #include "matrixKey.h"
-
- unsigned char KeyNum;
- unsigned int Password,count;
-
-
- void main()
- {
- LCD_Init();
- LCD_ShowString(1,1,"Helloworld");
- while(1)
- {
- KeyNum=MatrixKey();
- if(KeyNum){
- if(KeyNum<=10){ //s1~s10按下密码
- if(count<4){
- Password*=10;
- Password+=KeyNum%10; //这两句是用来实现四位密码的显示
- count++; //计数 防止按下的密码数超过四位
- }
- LCD_ShowNum(2,1,Password,4);//更新显示
- }
-
- if(KeyNum==11){ //s11设置为确认键
- if(Password==2345){
- LCD_ShowString(1,14,"OK ");
- Password=0; //密码清零
- count=0; //计数清零
- LCD_ShowNum(2,1,Password,4);//更新显示
- }
- else {LCD_ShowString(1,14,"ERR");
- Password=0; //密码清零
- count=0; //计数清零
- LCD_ShowNum(2,1,Password,4);//更新显示
- }
- }
-
- if(KeyNum==12){ //定义S12为取消键
- Password=0;
- count=0;
- LCD_ShowNum(2,1,Password,4);
- }
- }
- }
- }
中断溢出标志位:
TF=0(等于1产生中断);
TR0=1(定时器是否开启,给1开始,电机开始工作);
IE0、IT0:控制外部中断引脚,可以不配置
TH0\TL0 分开储存
代码优化,TMOD问题(不可位寻址)配置两个的时候,后面的会把前面的覆盖;
因此,可采用“与或”法设定TMOD
- #include <REGX52.H>
-
- void Timer0_Init(void) //1ms@11.0592MHz
- {
- TMOD &= 0xF0; //设置定时器模式
- TMOD |= 0x01; //设置定时器模式
- TL0 = 0x66; //设置定时器初值
- TH0 = 0xFC; //设置定时器初值
- TF0 = 0; //清除TF0标志
- TR0 = 1; //定时器0开始计时
- ET0=1; //下面三行为中断的配置
- EA=1;
- PT0=0;
- }
-
-
-
- void Timer0_Routine() interrupt 1 //中断函数
- {
- static unsigned int T0Count;
- TL0 = 0x66; //设置定时器初值
- TH0 = 0xFC; //设置定时器初值
- T0Count++;
- if(T0Count>=1000) //每隔1s
- {
- T0Count=0;
-
- }
- }
- #include <REGX52.H>
- #include "Delay.h"
-
-
-
- unsigned char Key()
- {
-
- unsigned char KeyNumber=0;
-
- if(P3_1==0){Delay(20);while(P3_1==0);Delay(20);KeyNumber=1;}
- if(P3_0==0){Delay(20);while(P3_0==0);Delay(20);KeyNumber=2;}
- if(P3_2==0){Delay(20);while(P3_2==0);Delay(20);KeyNumber=3;}
- if(P3_3==0){Delay(20);while(P3_3==0);Delay(20);KeyNumber=4;}
-
- return KeyNumber;
- }
- #include <REGX52.H>
- #include "Timer0.h"
- #include "key.h"
- #include <INTRINS.H>
-
- unsigned char KeyNumber,LEDmode;
- void main()
- {
- P2=0xfe; //与INTRINS.H中的循环左右移函数共同实现流水灯
- Timer0_Init(); //上电初始化
- while(1)
- {
- KeyNumber=Key();
- if(KeyNumber)
- {
- if(KeyNumber==1)
- {
- LEDmode++;
- if(LEDmode>=2) LEDmode=0;
- }
-
- }
-
- }
- }
-
-
-
- void Timer0_Routine() interrupt 1 //中断函数
- {
- static unsigned int T0Count;
- TH0=64535/256;
- TL0=64535%256;
- T0Count++;
- if(T0Count>=1000) //每隔1s
- {
- T0Count=0;
- if(LEDmode==0) P2=_crol_(P2,1);
- if(LEDmode==1) P2=_cror_(P2,1);
- }
- }
- #include <REGX52.H>
- #include "Delay.h"
- #include "LCD1602.h"
- #include "Timer0.h"
-
- unsigned char Sec,Min,Hour;
- void main()
- {
- LCD_Init();//³õʼ»¯
- Timer0_Init();
- LCD_ShowString(1,1,"CLOCK:");
- LCD_ShowString(2,1," : :");
- while(1)
- {
- LCD_ShowNum(2,1,Hour,2);
- LCD_ShowNum(2,4,Min,2);
- LCD_ShowNum(2,7,Sec,2);
- }
- }
-
- void Timer0_Routine() interrupt 1
- {
- static unsigned int T0Count;
- TL0 = 0x66;
- TH0 = 0xFC;
- T0Count++;
- if(T0Count>=1000)
- {
- T0Count=0;
- Sec++;
- if(Sec>=60)
- {
- Sec=0;
- Min++;
- if(Min>=60)
- {
- Min=0;
- Hour++;
- if(Hour>=24)
- {
- Hour=0;}
- }
- }
- }
-
- }
注:最少需要三根线实现双向通信:TXD,RXD,GND。VCC不一定需要,可独立供电。
差分信号优点:传送距离远(1km+) TTL与RS232(10m)
CAN总线:常用于汽车领域,因为使用的是差分信号传输,传输距离远、稳定。
通信方式的相关术语:
中间部分用来控制波特率,依靠定时器来约定速率,T1的溢出率通过分频后来控制收发器的采样时间。
SBUF:收发数据后,会产生相应的TI(发送中断)/RI(接收中断),继而进入中断函数,进行相应的中断函数内部的操作。
配置ES、EA,PS此时不需要配置,因为只有一个中断,不需要进行优先级判断。
配置好SCON和PCON,读SBUF,配置定时器T1,打开EA和ES,即串口可以开始工作。
故SCON=0x40
PCON
这里定时器1,没有定时器0,所有要把高位修改(不影响高低位配置用“”& |“”这两个方式)
选择8位自动重载模式
系统频率根据板子选择,波特率4800,波特率发生器选择8位自动重载,时钟12T
SCON = 0x50; EA=1;ES=1;
注:要分清这里是禁止了定时器1的中断功能,只是让它的溢出率去开启串口收发的功能,中断的产生是由于串口收发数据产生的中断。
串口中断函数模板:
- void UART_Routine() interrupt 4
- {
- if(RI==1)
- {
-
- RI=0; //复位清0
- }
- }
加-,低电平有效
OE: 使能,output enable,接低电平工作,高电平不工作。
RCLK:寄存器时钟,register clock
SRCLR:串行清零端
SRCLK:串行时钟
SER:串行数据
运行方式:类似队列
上述代码实现的是流水式的动画,也可以改变offset去实现逐帧动画。
定时器计时的缺点:1.精度不高 2.消耗单片机的CPU 3.断电不能继续计时
而时钟芯片精度高,且有备用电源,掉电可以用备用电源继续计时。
①:两种封装模式:直插封装和贴片封装 ②:分为三部分:电源部分,时钟部分,数据交互部分
秒,分,时,日,月,年,星期,年,wp(write protect,写保护),涓流充电
前两列的为 :命令字——
前八为指定读还是写,后八位读出或者写入指定的数据。
上升沿写入,下降沿读出。
结果会发现,数字到9后会直接到16……,这是因为寄存器数据是以BCD码存储的,只需将Second改为Second/16*10+Second%16,就可以转化成十进制,正常显示。
DS1302模块,LCD1602模块,独立按键key模块,定时器Timer0模块,延时函数模块;
主要分为四大部分:时钟模式选择,显示时间,设置时间(选择设置的时间位置,调整时间大小,利用定时器中断去实现选择的时间的位置的动态显示),更新显示新的时钟。
- #include <REGX52.H>
- #include "LCD1602.h"
- #include "DS1302.h"
- #include "Key.h"
- #include "Timer0.h"
- #include "Delay.h"
-
- unsigned char KeyNum,MODE,TimeSetSelect,TimeFlashFlag;
-
-
- /**
- * @brief 显示时间
- * @param 无
- * @retval 无
- */
- void TimeShow(void)
- {
- DS1302_ReadTime();
- LCD_ShowNum(1,1,DS1302_Time[0],2);
- LCD_ShowNum(1,4,DS1302_Time[1],2);
- LCD_ShowNum(1,7,DS1302_Time[2],2);
- LCD_ShowNum(2,1,DS1302_Time[3],2);
- LCD_ShowNum(2,4,DS1302_Time[4],2);
- LCD_ShowNum(2,7,DS1302_Time[5],2);
- }
-
- /**
- * @brief 设置时间,按键2选择设置的时间位置,按键3让时间++,按键4让时间--
- * @param 无
- * @retval 无
- */
- void TimeSet(void)
- {
- if(KeyNum==2)
- {
- TimeSetSelect++;
- TimeSetSelect %= 6;
- }
- if(KeyNum==3)
- {
- DS1302_Time[TimeSetSelect]++;
- if(DS1302_Time[0]>99){DS1302_Time[0]=0;}
- if(DS1302_Time[1]>12){DS1302_Time[1]=1;}
- if(DS1302_Time[1]==1 || DS1302_Time[1]==3 ||DS1302_Time[1]==5 ||DS1302_Time[1]==7
- || DS1302_Time[1]==8 || DS1302_Time[1]==10 ||DS1302_Time[1]==12)
- {
- if(DS1302_Time[2]>31){DS1302_Time[2]=1;}
- }else if(DS1302_Time[1]==4 || DS1302_Time[1]==6 ||DS1302_Time[1]==5 ||
- DS1302_Time[1]==9 || DS1302_Time[1]==11)
- {
- if(DS1302_Time[2]>30){DS1302_Time[2]=1;}
- }else if(DS1302_Time[1]==2)
- { if(DS1302_Time[0]%100!=0&&DS1302_Time[0]%4==0||DS1302_Time[0]%100==0&&DS1302_Time[0]%400==0)
- {
- if(DS1302_Time[2]>29){DS1302_Time[2]=1;}
- }else if(DS1302_Time[2]>28){DS1302_Time[2]=1;}
- }
- if(DS1302_Time[3]>23){DS1302_Time[3]=0;}
- if(DS1302_Time[4]>59){DS1302_Time[4]=0;}
- if(DS1302_Time[5]>59){DS1302_Time[5]=0;}
- }
- if(KeyNum==4)
- {
- DS1302_Time[TimeSetSelect]--;
- if(DS1302_Time[0]<0){DS1302_Time[0]=99;}
- if(DS1302_Time[1]<0){DS1302_Time[1]=12;}
- if(DS1302_Time[1]==1 || DS1302_Time[1]==3 ||DS1302_Time[1]==5 || DS1302_Time[1]==7
- || DS1302_Time[1]==8 || DS1302_Time[1]==10 ||DS1302_Time[1]==12)
- {
- if(DS1302_Time[2]<1){DS1302_Time[2]=31;}
- if(DS1302_Time[2]>31){DS1302_Time[2]=1;}
- }else if(DS1302_Time[1]==4 || DS1302_Time[1]==6 ||DS1302_Time[1]==5 || DS1302_Time[1]==9
- || DS1302_Time[1]==11)
- {
- if(DS1302_Time[2]<1){DS1302_Time[2]=30;}
- if(DS1302_Time[2]>30){DS1302_Time[2]=1;}
- }else if(DS1302_Time[1]==2)
- {
- if(DS1302_Time[0]%100!=0&&DS1302_Time[0]%4==0||DS1302_Time[0]%100==0&&DS1302_Time[0]%400==0)
- {
- if(DS1302_Time[2]<1){DS1302_Time[2]=29;}
- if(DS1302_Time[2]>29){DS1302_Time[2]=1;}
- }else
- {
- if(DS1302_Time[2]<1){DS1302_Time[2]=28;}
- if(DS1302_Time[2]>28){DS1302_Time[2]=1;}
- }
- }
- if(DS1302_Time[3]<0){DS1302_Time[3]=23;}
- if(DS1302_Time[4]<0){DS1302_Time[4]=59;}
- if(DS1302_Time[5]<0){DS1302_Time[5]=59;}
- }
- //动态显示选择位
- if(TimeSetSelect==0 && TimeFlashFlag==1 ){LCD_ShowString(1,1," ");}
- else {LCD_ShowNum(1,1,DS1302_Time[0],2);}
- if(TimeSetSelect==1 && TimeFlashFlag==1 ){LCD_ShowString(1,4," ");}
- else {LCD_ShowNum(1,4,DS1302_Time[1],2);}
- if(TimeSetSelect==2 && TimeFlashFlag==1 ){LCD_ShowString(1,7," ");}
- else {LCD_ShowNum(1,7,DS1302_Time[2],2);}
- if(TimeSetSelect==3 && TimeFlashFlag==1 ){LCD_ShowString(2,1," ");}
- else {LCD_ShowNum(2,1,DS1302_Time[3],2);}
- if(TimeSetSelect==4 && TimeFlashFlag==1 ){LCD_ShowString(2,4," ");}
- else {LCD_ShowNum(2,4,DS1302_Time[4],2);}
- if(TimeSetSelect==5 && TimeFlashFlag==1 ){LCD_ShowString(2,7," ");}
- else {LCD_ShowNum(2,7,DS1302_Time[5],2);}
- }
-
-
-
- void main()
- {
- Timer0_Init();
- LCD_Init();
- DS1302_Init();
- DS1302_WriteByte(0x8e,0x00);
-
- LCD_ShowString(1,1," - - ");
- LCD_ShowString(2,1," : : ");
- DS1302_SetTime();
-
- while(1)
- {
- //通过按键1控制时钟的模式,模式0为显示时钟,模式1为设置时间
- KeyNum=key();
- if(KeyNum==1)
- {
- if(MODE==0){MODE=1;TimeSetSelect=0;}
- else if(MODE==1) {MODE=0;DS1302_SetTime();}
- }
- switch(MODE)
- {
- case 0:TimeShow();break;
- case 1:TimeSet();break;
- }
- }
-
- }
-
- //利用定时器中断来动态显示选择的时间位置
- void Timer0_Routine() interrupt 1
- {
- static unsigned int T0Count;
- TL0 = 0x66;
- TH0 = 0xFC;
- T0Count++;
- if(T0Count>=1000)
- {
- T0Count=0;
- TimeFlashFlag=!TimeFlashFlag;
- }
- }
NPN:高电平导通 PNP:低电平导通
由P15的高低电平取反控制BZ的高低电平
一般以四分音符为一个基准
RAM:存储速度快,但是掉电丢失 ROM:掉电不丢失,但是速度慢。
引脚及应用电路
I2C通信 时序结构:
先进行位声明,再分别编写子函数,开始,结束,发送和接受一个字节,发送和接收应答位
先定义一下AT24C02的地址,写是0xA0,读是0xA1;
再用I2C里的函数去编写写入一个字节和读出一个字节的函数
用独立按键控制想要写入的数据,并读出显示在LCD上,断电不丢失。
这样就不用像原来一样在检测时停在while死循环里,影响主函数进程
先在main模块的中断函数里加上一个计数定时器的T0Count2,这样每隔一段时间就会调用一下NixieLoop函数,而NixieLoop函数会不断扫描并在数码管上显示每一位数字。NixieSetBuf函数会根据输入的位置和数字改变Buf数组里的值,继而让NixieLoop扫描显示对应的值。
- #include <REGX52.H>
- #include "Timer0.h"
- #include "key.h"
- #include "Delay.h"
- #include "Nixie.h"
- #include "AT24C02.h"
-
- unsigned char KeyNum;
- unsigned char Min,Sec,Minisec;
- unsigned char Runflag;
-
- void main()
- {
- Timer0_Init();
-
- while(1)
- {
- KeyNum=Key();
- if(KeyNum==1) //按键1控制开始和停止计时
- {
- Runflag=!Runflag;
- }
- if(KeyNum==2) //按键2清0
- {
- Min=0;
- Sec=0;
- Minisec=0;
- }
- if(KeyNum==3) //按键3将数据写入AT
- {
- AT24C02_WriteByte(0,Min);
- Delay(5);
- AT24C02_WriteByte(1,Sec);
- Delay(5);
- AT24C02_WriteByte(2,Minisec);
- Delay(5);
- }
- if(KeyNum==4) //按键4读出数据
- {
- Min=AT24C02_ReadByte(0);
- Sec=AT24C02_ReadByte(1);
- Minisec=AT24C02_ReadByte(2);
- }
- Nixie_SetBuf(1,Min/10);
- Nixie_SetBuf(2,Min%10);
- Nixie_SetBuf(3,11);
- Nixie_SetBuf(4,Sec/10);
- Nixie_SetBuf(5,Sec%10);
- Nixie_SetBuf(6,11);
- Nixie_SetBuf(7,Minisec/10);
- Nixie_SetBuf(8,Minisec%10);
-
- }
- }
-
- //计时中断函数
- void Sec_Loop()
- {
- if(Runflag)
- {
- Minisec++;
- if(Minisec>=100)
- {
- Minisec=0;
- Sec++;
- if(Sec>=60)
- {
- Sec=0;
- Min++;
- if(Min>=60)
- {
- Min=0;
- }
- }
- }
- }
- }
-
-
- void Timer0_Routine() interrupt 1 //ÖжϺ¯Êý
- {
- static unsigned int T0Count1,T0Count2,T0Count3;
- TL0 = 0x66; //ÉèÖö¨Ê±Æ÷³õÖµ
- TH0 = 0xFC; //ÉèÖö¨Ê±Æ÷³õÖµ
- T0Count1++;
- if(T0Count1>=20)
- {
- T0Count1=0;
- Key_Loop();
- }
- T0Count2++;
- if(T0Count2>=2)
- {
- T0Count2=0;
- Nixie_Loop();
- }
- T0Count3++;
- if(T0Count3>=10)
- {
- T0Count3=0;
- Sec_Loop();
- }
- }
最后一列分别是:温度传感器(内部的模拟温度传感器,能进行数据的转换),存储高报警位的EEPROM,存储低报警位的EEPROM,调节精度,校验码
前两个字节分别存储数据的低位和高位
总体思路:先发送温度转换的指令,再发送读数据的指令。因此,我们接下来要学习,如何通过单总线来发送数据和接收数据。
本节需要的指令SKIP ROM,CONVERT T:让温度转换器进行数据的转换,READ SCRATCHPAD:读暂存器,依次读出每一个字节。
包括符号,整数部分,小数部分,其中负数以补码形式存储
- #include <REGX52.H>
- #include "DS18B20.h"
- #include "key.h"
- #include "LCD1602.h"
- #include "Delay.h"
- #include "AT24C02.h"
- #include "Timer0.h"
-
- float T,TShow;
- char TLow,THigh;
- unsigned char KeyNum;
-
- void main()
- {
- DS18B20_ConverT();
- Delay(1000);
- THigh=AT24C02_ReadByte(0);
- TLow=AT24C02_ReadByte(1);
- if(THigh>125 || TLow<-55 || THigh<=TLow)
- {
- THigh=20;
- TLow=15;
- }
- LCD_Init();
- LCD_ShowString(1,1,"T:");
- LCD_ShowString(2,1,"TH:");
- LCD_ShowString(2,9,"TL:");
- LCD_ShowSignedNum(2,4,THigh,3);
- LCD_ShowSignedNum(2,12,TLow,3);
- Timer0_Init();
- while(1)
- {
- KeyNum=Key();
- /*温度读取及显示*/
- DS18B20_ConverT();
- T=DS18B20_ReadT();
- if(T<0)
- {
- LCD_ShowChar(1,3,'-');
- TShow=-T;
- }
- else
- {
- LCD_ShowChar(1,3,'+');
- TShow=T;
- }
- LCD_ShowNum(1,4,TShow,3);
- LCD_ShowChar(1,7,'.');
- LCD_ShowNum(1,8,(unsigned long)(TShow*100)%100,2);
-
- /*阈值判断及显示*/
- if(KeyNum)
- {
- if(KeyNum==1)
- {
- THigh++;
- if(THigh>125){THigh=125;}
- }
- if(KeyNum==2)
- {
- THigh--;
- if(THigh<=TLow){THigh++;}
- }
- if(KeyNum==3)
- {
- TLow++;
- if(TLow>=THigh){TLow--;}
- }
- if(KeyNum==4)
- {
- TLow--;
- if(TLow<-55){TLow=-55;}
- }
- LCD_ShowSignedNum(2,4,THigh,3);
- LCD_ShowSignedNum(2,12,TLow,3);
- AT24C02_WriteByte(0,THigh);
- Delay(5);
- AT24C02_WriteByte(1,TLow);
- Delay(5);
- }
- if(T>THigh)
- {
- LCD_ShowString(1,13,"OV:H");
- }
- else if(T<TLow)
- {
- LCD_ShowString(1,13,"OV:L");
- }
- else {LCD_ShowString(1,13,"OV: ");}
- }
- }
-
-
- void Timer0_Routine() interrupt 1 //中断函数
- {
- static unsigned int T0Count;
- TL0 = 0x66;
- TH0 = 0xFC;
- T0Count++;
- if(T0Count>=20)
- {
- T0Count=0;
- Key_Loop();
- }
- }
为防止定时器扫描按键时会打断OneWire的传送与接收
可以在OneWire里先关闭EA,再打开EA。
之后可以在main函数里调用流动的指令,实现流动字幕
大功率器件直接驱动:只能使电机朝着一个方向转,不具备调换电机正反方向的功能。
H桥驱动:可以控制电机正反转。
给电全速转,不给电不转,利用惯性,可以设置一个在周期内高电平与低电平的时间,使之呈现中间速度
- #include <REGX52.H>
- #include "Delay.h"
- #include "key.h"
- #include "Nixie.h"
- #include "Timer0.h"
-
- sbit Motor=P1^0; //位声明
-
- unsigned char Counter,Compare;
- unsigned char KeyNum,Speed;
-
- void main()
- {
- Timer0_Init();
- while(1)
- {
- KeyNum=Key();
- if(KeyNum==1)
- {
- Speed++;
- Speed%=4;
- if(Speed==0){Compare=0;}
- if(Speed==1){Compare=50;}
- if(Speed==2){Compare=75;}
- if(Speed==3){Compare=100;}
-
- }
- Nixie(1,Speed);
- }
- }
-
- void Timer0_Routine() interrupt 1
- {
- TL0 = 0xA4;
- TH0 = 0xFF;
- Counter++;
- if(Counter>=100) {Counter=0;}
- if(Counter<Compare)
- {
- Motor=1;
- }
- else
- {
- Motor=0;
- }
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。