1、单片机程序知识点剖析单片机程序知识点按键扫描支持连续按一般思路u8 KEY_Scan(void) if(KEY按下) delay_ms(10);/延时10-20ms,防抖。 if(KEY确实按下) return KEY_Value; return 无效值; 按键扫描不支持连续按一般思路u8 KEY_Scan(void) static u8 key_up=1; if(key_up & KEY按下) delay_ms(10);/延时,防抖 key_up=0;/标记这次key已经按下 if(KEY确实按下) return KEY_VALUE; else if(KEY没有按下) key_up=1; r
2、eturn 没有按下 串口通讯2void UART() interrupt 4 if(RI) /检测是否接收完成 num = SBUF;/num 取出接收缓存器的值 P1 = SBUF; num+; RI = 0; SBUF = num; while(!TI); TI = 0;两个等于控制占空比timer0() interrupt 1 t+; /每次定时器溢出加1 if(t=250) /PWM周期 100个单位 t=0; /使t=0,开始新的PWM周期 P1=0x00; /输出端口 /按照当前占空比切换输出为高电平 if(PWM_T=t) P1=0xff; 数码管动态显示 unsigned c
3、har code DuanMa=0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71; / 显示段码值0Funsigned char code WeiMa=0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f;/分别对应相应的数码管点亮,即位码while(1) DataPort=WeiMai; /取位码 LATCH2=1; /位锁存 LATCH2=0;/取显示数据,段码DataPort=DuanManum+i; LATCH1=1; /段锁存 LATCH1=0; /
4、 扫描间隙延时,时间太长会闪烁,太短 会 造成重影Delay(200); i+; /检测8位扫描完全结束?如扫描完成则从第一个开始再次扫描8位if(8=i) i=0;数码管动态显示/*- 显示函数,用于动态扫描数码管 输入参数 FirstBit 表示需要显示的第一位,如赋值2表示从第三个数码管开始显示,如输入0表示从第一个显示。 Num表示需要显示的位数,如需要显示99两位数值则该值输入2-*/ /存储显示值的数组unsigned char TempData10; /分解显示信息,如要显示68, 则68/10=6 68%10=8TempData0=dofly_DuanManum/10; Tem
5、pData1=dofly_DuanManum%10;void Display(unsigned char FirstBit,unsigned char Num) unsigned char i; for(i=0;iNum;i+) DataPort=0; /清空数据,防止有交替重影 LATCH1=1; /段锁存 LATCH1=0; DataPort=WeiMai+FirstBit; /取位码 LATCH2=1; /位锁存 LATCH2=0; DataPort=TempDatai; /取显示数据,段码 LATCH1=1; /段锁存 LATCH1=0; Delay(200); / 扫描间隙延时,时间
6、太长/ 会闪烁,太短会造成重影 动态显示消隐方法if(num1000) /如果小于1000则千位不显示TempData0=0;else TempData0=dofly_DuanManum/1000;/分解显示信息,如要显示68,则68/10=6 / 68%10=8 /如果小于100则千位和百位都不显示if(num100) TempData1=0;elseTempData1=dofly_DuanMa(num%1000)/100;/如果小于10,则千位、百位和十位/ 都不显示if(num10) TempData2=0;elseTempData2=dofly_DuanMa(num%1000)%100
7、)/10;使用中断实现分频器的功能/*- 定时器中断子程序-*/void Timer0_isr(void) interrupt 1 using 1 static unsigned char i; /重新赋值 12M晶振计算,指令周期1uS,500x2=1mS方波 TH0=(65536-500)/256; TL0=(65536-500)%256; i+; P1=i; /*P1口8路输出不同频率,相当于一个分频器,高频用示波器测量,低频可以直接用led观测P1.0输出1ms方波,P1.1输出2ms,p1.2输出4ms,以此类推*/按键行扫描程序/*- 按键扫描函数,返回扫描键值-*/ /键盘扫描函
8、数,使用行列逐级扫描法unsigned char KeyScan(void) unsigned char Val; KeyPort=0xf0;/高四位置高,低四位拉低 if(KeyPort!=0xf0)/表示有按键按下 DelayMs(10); /去抖 if(KeyPort!=0xf0)/表示有按键按下 KeyPort=0xfe; /检测第一行 if(KeyPort!=0xfe) Val=KeyPort&0xf0; Val+=0x0e; while(KeyPort!=0xfe); DelayMs(10); /去抖 while(KeyPort!=0xfe); return Val; KeyPor
9、t=0xfd; /检测第二行 if(KeyPort!=0xfd) Val=KeyPort&0xf0; Val+=0x0d; while(KeyPort!=0xfd); DelayMs(10); /去抖 while(KeyPort!=0xfd); return Val; KeyPort=0xfb; /检测第三行 if(KeyPort!=0xfb) Val=KeyPort&0xf0; Val+=0x0b; /松手检测 while(KeyPort!=0xfb); DelayMs(10); /去抖 while(KeyPort!=0xfb); return Val; KeyPort=0xf7; /检测第
10、四行 if(KeyPort!=0xf7) Val=KeyPort&0xf0; Val+=0x07; while(KeyPort!=0xf7); DelayMs(10); /去抖 while(KeyPort!=0xf7); return Val; return 0xff;步进电机1相励磁驱动 /A相通电,其他相断电#define oil_A1 A1=1;B1=0;C1=0;D1=0; /B相通电,其他相断电#define Coil_B1 A1=0;B1=1;C1=0;D1=0; /C相通电,其他相断电#define Coil_C1 A1=0;B1=0;C1=1;D1=0; /D相通电,其他相断电
11、#define Coil_D1A1=0;B1=0;C1=0;D1=1; /全部断电#define Coil_OFF A1=0;B1=0;C1=0;D1=0;while(1) Coil_A1 /改变以下参数可以调整电机转速 ,数字越小,转速越大,力矩越小 DelayMs(Speed); Coil_B1 DelayMs(Speed); Coil_C1 DelayMs(Speed); Coil_D1 DelayMs(Speed); 步进电机1-2相励磁驱动if(times=Speed) times=0; switch(i) case 0:Coil_A1;i+;break; case 1:Coil_A
12、B1;i+;break; case 2:Coil_B1;i+;break; case 3:Coil_BC1;i+;break; case 4:Coil_C1;i+;break; case 5:Coil_CD1;i+;break; case 6:Coil_D1;i+;break; case 7:Coil_DA1;i+;break; case 8:i=0;break; default:break; else times+;电机按键控制sbit DCOUT1 = P11;/电机信号输出端口1switch(num)/电机1改变运行状态,数码管显示运行状态 case 1:DCOUT1=!DCOUT1;
13、TempData0=0x5E; /d TempData1=0x39; /C TempData2=0x06; /1 if(DCOUT1) TempData5=0x3F; /O TempData6=0x54; /n TempData7=0; else TempData5=0x3F; /O TempData6=0x71; /F TempData7=0x71; /F break;LCD1602*/判断液晶忙,如果忙则等待void Read_Busy() uchar busy; P0 = 0xff; RS = 0; RW = 1; do EN = 1; busy = P0; EN = 0; while(
14、busy & 0x80);/写LCD1602命令一个字节void Write_Cmd(uchar cmd) Read_Busy();/判断忙 RS = 0; RW = 0; P0 = cmd; EN = 1; EN = 0;/写一个字节数据void Write_Dat(uchar dat) Read_Busy(); RS = 1; RW = 0; P0 = dat; EN = 1; EN = 0;LCD1602/*- 判忙函数-*/ bit LCD_Check_Busy(void) DataPort= 0xFF; RS_CLR; RW_SET; EN_CLR; _nop_(); EN_SET;
15、 return (bit)(DataPort & 0x80); /*- 写入命令函数-*/ void LCD_Write_Com(unsigned char com) while(LCD_Check_Busy(); /忙则等待 DelayMs(5); RS_CLR; RW_CLR; EN_SET; DataPort= com; _nop_(); EN_CLR; /*- 写入数据函数-*/ void LCD_Write_Data(unsigned char Data) while(LCD_Check_Busy(); /忙则等待 DelayMs(5); RS_SET; RW_CLR; EN_SET
16、; DataPort= Data; _nop_(); EN_CLR; /*- 写入字符串函数-*/ void LCD_Write_String(uchar x,uchar y,uchar *s) if (y = 0) LCD_Write_Com(0x80 + x); else CD_Write_Com(0xC0 + x); while (*s) LCD_Write_Data( *s); s +; /*- 写入字符函数-*/ void LCD_Write_Char(uchar x,uchar y,uchar Data) if (y = 0) LCD_Write_Com(0x80 + x); el
17、se LCD_Write_Com(0xC0 + x); LCD_Write_Data( Data); LCD1602键盘输入显示while (1) num=KeyPro(); if(num!=0xff) if(i=0)&(j=0)/回到第一个字符时清屏 LCD_Clear();/清屏 /依次显示输入字符 LCD_Write_Char(0+i,0+j,dofly_codenum); i+; if(i=16)/如果第一行显示满,转到第二行 i=0;j+;/如果2行都显示满,清屏后重新从第一行 显示 if(j=2) j=0; LCD1602动态显示while (1) i = 1; p = ; LCD
18、_Clear(); LCD_Write_String(2,0,Welcome to); DelayMs(250); while (*p) LCD_Write_Char(i,1,*p); i +; p +; DelayMs(250); DelayMs(250); LCD602滚动显示void main(void) LCD_Init(); LCD_Clear();/清屏 LCD_Write_Char(7,0,o); LCD_Write_Char(8,0,k); LCD_Write_String(1,1,);while (1) DelayMs(200); LCD_Write_Com(0x18); /
19、左平移画面 / 0x1C 是右平移 LCD1602平移显示while (1) pa = Welcome to; pb = ; LCD_Clear(); LCD_Write_String(2,0,pa); /显示2行信息 LCD_Write_String(1,1,pb); for(i=0;i8;i+)DelayMs(250); /延时2s左右 LCD_Clear(); /清屏显示其他信息 i = 2; while (*pa) /循环输入方式显示2行信息 LCD_Write_Char(i,0,*pa); i +; pa +; DelayMs(250); i=1; while (*pb) LCD_W
20、rite_Char(i,1,*pb); i +; pb +; DelayMs(250); DelayMs(250); LCD1602/*显示一个字节数据void DisplayOneChar (uchar X,uchar Y,uchar DData) /Y=1显示第二行,Y=0显示第一行 if(Y) X|=0X40; X|=0X80; Lcd1602_Write_Cmd(X); /X用来选择哪位 Lcd1602_Write_Data(DData); /DData用来 写数据/显示一个字节字符void DisplayOneStr (uchar X,uchar Y,uchar DData) Dis
21、playOneChar (X+,Y,DData/16 + 0); DisplayOneChar (X,Y,DData%16 + 0);/显示字符串void LcdShowStr(uchar x,uchar y,uchar *str) LcdSetCursor(x,y); /当前字符的坐标 while(*str !=0)Lcd1602_Write_Data(*str+);void InitLcd1602() /1602初始化 /打开5*8,8位数据 Lcd1602_Write_Cmd(0x38); Lcd1602_Write_Cmd(0x0c); Lcd1602_Write_Cmd(0x06);
22、 Lcd1602_Write_Cmd(0x01); /清屏 DS1302突发模式些时钟while(1) Read_DS1302_Time();/时钟突发模式读 DisplayOneStr (5,0,TimeData6); /年 DisplayOneChar (7,0,-); /- DisplayOneStr (8,0,TimeData4); /月 DisplayOneChar (10,0,-); /- DisplayOneStr (11,0,TimeData3);/日 DisplayOneChar (13,0,-); /- DisplayOneStr (14,0,TimeData5);/星期
23、DisplayOneStr (6,1,TimeData2); /时 DisplayOneChar (8,1,:); /: DisplayOneStr (9,1,TimeData1); /分 DisplayOneChar (11,1,:); /: DisplayOneStr (12,1,TimeData0);/秒 Delay_Ms(1000); /延时1秒8*8点阵左移显示while(1) for(j = 0 ; j 16 ; j+) for(i = 0 ; i 50 ; i+) temp = 0x7f; for(k = 0 ; k 1)|0x80;红外接受1void int0() interr
24、upt 0 /定义外部中断0static uchar i; static bit startflag; /开始储存脉宽标志位if(startflag) /开始接收脉宽检测/*判断是否是引导码,底电平9000us+高4500us,这个自己可以算我以11.0592来算了NEC协议的引导码低8000-10000+高4000-5000如果已经接收了引导码那么i不会被置0就会开始依次存入脉宽*/如果是引导码那么执行i=0把他存到 / IRdata的第一个位 if( (IRtime = 32) )i = 0; / IRdatai = IRtime; /以T0的溢出次数来/ 计算脉宽,把这个时间/ 存到数组里面到后面判断 IRtime = 0;/计数清零,下一个下降沿的时/ 候在存入脉宽i+; /计数脉宽存入的次数if(i = 33) IRok = 1; /那么表示脉宽检测完毕 i = 0; /把脉宽计数清零准备下次存入 else IRtime = 0; /引导码开始进入把脉宽计数/ 清零开始计数