上升沿写入,下降沿读出
发布时间:2025-06-24 19:55:51 作者:北方职教升学中心 阅读量:298
结构简单,在生活和工业控制领域大有所用。通过独立按键控制led完成二进制
#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--;代替最后两句,完成二进制运算。
上升沿写入,下降沿读出。
3-4、下面为共阳极的原理图:
5.STC89C52实现数字显示
①原理图是共阴极(上面给0、4)定义的Animation是放在RAM中的,有空间限制,浪费RAM空间。模块化编程
1)驱动,先会用,后续有详细内容:
2)模块化,功能函数用点C文件写,点H文件声明函数,在main函数文件引入头文件直接调用:
3)注意事项
4)预编译
5)延时函数文件
6)头文件延迟
7)主函数文件程序入口:
8)数码管模块,用到的头文件要引用:
9)数码管模块头文件
10)函数调用
11)显示
5-2 、定时器/计算器、
配置好SCON和PCON,读SBUF,配置定时器T1,打开EA和ES,即串口可以开始工作。
8-2.实际配置串口
1)将延迟函数复制过来并导入工程里面;
2)配置串口控制寄存器,配置模式1最常用,REN允许接收给1,不允许接收给0(也可以给1外面不给发就行);
3)TI、


包括符号,整数部分,小数部分,其中负数以补码形式存储
13.2示例代码
1-DS18B20温度读取
①:整体思路——先写OneWire模块(包括初始化,发送一位,读出一位,发送一个字节,接收一个字节),再写DS18B20模块(包括温度转换指令函数,读取数据函数),最后编写main函数。

配置ES、下给1亮)

②138译码器:输入3(ABC,读的时候是从下读 C B A )个口,控制输出8个口,输出口连接共阴极的,是0还是1,在这里控制:使能端连接(按下图给1和0就可以用了)

通过CBA给数字0和1二进制转换10进制(得到数字几)就控制Y几,Y0头上“—”是表示低电平有效(即给0):

③双向缓冲,高电平往低电平送数据

CC2电容作用:滤波电容,稳定电源,确定电路稳定性,提高电路工作性能可靠运行;
RP4:排阻,限流,防止电流过大
④这里的P01......P07,就是用P0口,后面代码就是通过P0口控制灯的

只有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); }
要显示的数字对应的值

4-2、单片机的一些基础项目2-1、2.编写串口中断函数

串口中断函数模板:
void UART_Routine() interrupt 4{ if(RI==1) { RI=0; //复位清0 }}
3.整体代码

9-1LED点阵屏
1.介绍:

2.显示原理
3.相关图
①:led矩阵图——经测试,P0控制列,D控制行

②:开发版引脚对应关系:

③:74HC595

加-,低电平有效
OE: 使能,output enable,接低电平工作,高电平不工作。IT0:控制外部中断引脚,可以不配置
4.定时器配置 TH0\TL0

TH0\TL0 分开储存

代码优化,TMOD问题(不可位寻址)配置两个的时候,后面的会把前面的覆盖;
因此,可采用“与或”法设定TMOD


5.中断配置T0-->ET0=1--EA=1,PT0=0

6.定时器配置完成,模块化编程
#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;}
7.定时器中断函数模板
void Timer0_Routine() interrupt 1 //中断函数{ static unsigned int T0Count; TL0 = 0x66; //设置定时器初值 TH0 = 0xFC; //设置定时器初值 T0Count++; if(T0Count>=1000) //每隔1s { T0Count=0; }}
8.独立按键模块
#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;}
9.主函数
#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); }}

7-2.时钟
1.把LCD1602液晶显示、往右升高,往左降低:相邻半音黑白,1对应中央C1,i表示升即C2部分,降低8度下面加一个点,降低2个8度,下面加两个点(白键);相邻两个键为半音#:升高半音,b:降低半音。 同时,学习使用单片机是了解计算机原理与结构的最佳选择。按一次亮,按一次灭。

2.AT24C02介绍

引脚及应用电路


3. I2C总线


I2C通信 时序结构:








4.示例程序
1——用独立按键设置想要写入的数据,并读出显示在LCD上,断电不丢失。通过独立按键控制led闪烁#include <REGX52.H>void main(){ while(1) { if(P3_1==0)//低电平 按下按键接地为0 { P2_0=0;//d1亮 } else { P2_0=1; } }}
3-2、

3.电机调速——PWM介绍
给电全速转,不给电不转,利用惯性,可以设置一个在周期内高电平与低电平的时间,使之呈现中间速度


15-2 示例代码
1.LED呼吸灯——用来理解PWM

2.电机调速
①:创建新工程,需要用到的模块:Delay,Timer0,Nixie,key
②:main函数编写
#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; }}
16-1 AD/DA
1.介绍

2.硬件电路模型

3.实际硬件电路


4.运算放大器

四大运算放大器的经典电路


5.DA原理


6.AD


7.AD/DA性能指标

8.XPT2046

SPI通信:CS:片选,DCLK:时钟,DIN:数据输入,DOUT:数据输出
每个从机单独有个CS与主机连接,剩下三根线共用

16-2.实例代码
1.AD模数转换——在LCD上显示滑变,热敏电阻,光敏电阻的值
①:需要的模块:Delay,LCD,XPT2046
②:XPT2046模块的编写
先进行位声明,再写读取AD值的函数,读AD值,要给一个命令字,说明以什么模式读取的什么部位的AD值
#include <REGX52.H>#include "Delay.h"sbit XPT2046_CS=P3^5;sbit XPT2046_DCLK=P3^6;sbit XPT2046_DIN=P3^4;sbit XPT2046_DOUT=P3^7;unsigned int XPT2046_ReadAD(unsigned char Command){ unsigned char i; unsigned int ADValue; XPT2046_DCLK=0; XPT2046_CS=0; for(i=0;i<8;i++) { XPT2046_DIN=Command&(0x80>>i); XPT2046_DCLK=1; Delay(1); XPT2046_DCLK=0; } for(i=0;i<16;i++) { XPT2046_DCLK=1; Delay(1); XPT2046_DCLK=0; if(XPT2046_DOUT) {ADValue|=(0x8000>>i);} } XPT2046_CS=1; if(Command&0x08) { return ADValue>>8; } else { return ADValue>>4; }}

③:main函数

2.DA数模转换——实现呼吸灯
①:用PWM的工程改造即可
②:换IO口,把Motor换成DA的口,再结合PWM调速,即可实现。中断系统和IO口
等一系列电脑的常用硬件功能 单片机的任务是信息采集(依靠传感器)、通过独立按键控制led状态#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>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); }

2-1、2.编写串口中断函数

void UART_Routine() interrupt 4{ if(RI==1) { RI=0; //复位清0 }}


2.显示原理









#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>void main(){ while(1) { if(P3_1==0)//低电平 按下按键接地为0 { P2_0=0;//d1亮 } else { P2_0=1; } }}
3-2、




#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; }}














#include <REGX52.H>#include "Delay.h"sbit XPT2046_CS=P3^5;sbit XPT2046_DCLK=P3^6;sbit XPT2046_DIN=P3^4;sbit XPT2046_DOUT=P3^7;unsigned int XPT2046_ReadAD(unsigned char Command){ unsigned char i; unsigned int ADValue; XPT2046_DCLK=0; XPT2046_CS=0; for(i=0;i<8;i++) { XPT2046_DIN=Command&(0x80>>i); XPT2046_DCLK=1; Delay(1); XPT2046_DCLK=0; } for(i=0;i<16;i++) { XPT2046_DCLK=1; Delay(1); XPT2046_DCLK=0; if(XPT2046_DOUT) {ADValue|=(0x8000>>i);} } XPT2046_CS=1; if(Command&0x08) { return ADValue>>8; } else { return ADValue>>4; }}


#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;//按位取反 }}}
取消按键时的抖动,使单片机稳定判断状态。NixieSetBuf函数会根据输入的位置和数字改变Buf数组里的值,继而让NixieLoop扫描显示对应的值。
2.蜂鸣器演奏音乐—有时间再补
12.AT24C02,I2C总线
1.存储器介绍
RAM:存储速度快,但是掉电丢失 ROM:掉电不丢失,但是速度慢。
2.时钟芯片的引脚定义和应用电路
①:两种封装模式:直插封装和贴片封装 ②:分为三部分:电源部分,时钟部分,数据交互部分
3. 内部结构框图
4.内部寄存器的定义
秒,分,时,日,月,年,星期,年,wp(write protect,写保护),涓流充电
前两列的为 :命令字——
5. 时序图
前八为指定读还是写,后八位读出或者写入指定的数据。
一、②:编写MatrixKey(矩阵)代码
#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"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); }} }
快速生成常用格式代码:
设置,完成后双击就可以生成了:
6-2.矩阵键盘密码锁
1):把6-1文件全部cv到6-2工程文件中
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); }} }}
7.定时器介绍
1)介绍,Delay前面CPU是一直在等的,用定时器在Delay时可以去检测按键,提高CPU利用率:
2)模式1最常用:
3)模式:时钟--计数最大65535(计数系统TL0\TH0:每来一个脉冲+1方法计数)-TF0(标志位,到最大了回到0)-中断:
4)非门与门图形为控制部分(TR0是否启动暂定)
5)定时器部分:
6)时钟可以由系统提供(上图,晶振),也可以由外部T0P提供(如下图引脚)
7)C/T,给1连上面为控制器,给0连接下面为定时器(如下图):
8)中断系统:
9)中断资源
10)定时器和中断系统
11)定时器相关寄存器
7-1.独立按键控制流水灯的模式
1.TMOD寄存器工作模式,定时器0配置使用(不可位寻址,只能整体赋值)
2.定时器模式1:门控端给0,就是tr0单独控制:C/T,T这里有一横表示低电平有效,就给0是用T(定时器模式),给1用C(控制器模式),M1,M0工作模式选择
3.TCON控制寄存器(可位寻址,可以单独每一位赋值)
中断溢出标志位:
TF=0(等于1产生中断);
TR0=1(定时器是否开启,给1开始,电机开始工作);
IE0、EA,PS此时不需要配置,因为只有一个中断,不需要进行优先级判断。流水灯
#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(); }}
位运算做法:
2-4、点亮一个led灯
#include <REGX52.H>void main(){ P2=0x7f;//1111 1110 d1 16 15 //0111 1111 d8 7 16 //1011 1111 d7 11 16 }
通过高低电平控制led亮否
2-2、
④: 编写主函数
#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(); }}
13.1 DS18B20——温度传感器
1.介绍
2.引脚及应用电路
3.内部结构框图
最后一列分别是:温度传感器(内部的模拟温度传感器,能进行数据的转换),存储高报警位的EEPROM,存储低报警位的EEPROM,调节精度,校验码
前两个字节分别存储数据的低位和高位
总体思路:先发送温度转换的指令,再发送读数据的指令。位选影响造成串位,如下代码消除;
了解
5-1、行需通过74HC595来间接控制。单片机跟计算机相比,单片机算是一个袖珍版计算机,一个芯片就能构成完整的计算机系统。
RCLK:寄存器时钟,register clock
SRCLR:串行清零端
SRCLK:串行时钟
SER:串行数据
运行方式:类似队列
④:总结:使用步骤:进行行列的选择——列由P0口控制,因此给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 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 <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); }}
注释掉上面的延时调用,旁边的管会有些影响,需要消影,段选、但在性能上,与计算机相差甚远,但单片机成本低、只读存储器RAM、3)实例代码
1.蜂鸣器鸣响
①:蜂鸣器模块函数
②:主函数——按下独立按键,在数码管上显示按的第几个键,并且蜂鸣器鸣响。VCC不一定需要,可独立供电。
3-3、
3)编写子函数——控制74HC595把字节数据输出给D的8个引脚。
9-2.点阵屏的驱动代码
示例代码1-点阵屏显示图形
1)sfr与sbit,可位寻址与不可位寻址。定时器、
①:程序编写整体思路:编写I2C模块,AT24C02模块,main模块
②:编写I2C模块
先进行位声明,再分别编写子函数,开始,结束,发送和接受一个字节,发送和接收应答位
③:编写AT24C02模块
先定义一下AT24C02的地址,写是0xA0,读是0xA1;
再用I2C里的函数去编写写入一个字节和读出一个字节的函数
④:编写main模块
用独立按键控制想要写入的数据,并读出显示在LCD上,断电不丢失。
通信方式的相关术语:
④51单片机里的UART串口
中间部分用来控制波特率,依靠定时器来约定速率,T1的溢出率通过分频后来控制收发器的采样时间。
#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; }}
11.蜂鸣器
1)介绍
NPN:高电平导通 PNP:低电平导通
由P15的高低电平取反控制BZ的高低电平
2)乐理知识
①:介绍C1-C2升高8度。
1个机器周期 = 6个状态周期 = 12个时钟(振荡)周期
时钟周期:即单片机的基本时间单位,若晶体的频率=12MHZ,那时钟周期 = 1/12MHZ,一个时钟周期 = 1/12MHZ = 1/12000 000每秒
机器周期:即12x1/12 000 000 =0.000001s = 1us,访问一次ROM取指令的时间就是1us
2.单片机命名规则
3.单片机内部结构
重点需记:单片机管脚
1.电源:Vcc:正极 Gnd:负极 2.XTAL:单片机时钟引脚,外接晶振
3.RST:复位
4.开发板介绍
开发板原理图
二、内部集成了中央处理器CPU、所以可以加个code,把它放在flash里,但此时不可在主函数里改变数组内容。
17-1 红外遥控
1.介绍

2.硬件电路

3.基本发送与接收

4.NEC编码


5.51单片机的外部中断


17-2.实例代码
1.红外遥控显示按键键码
①:配置外部中断INT0,并编写设置定时器时间和读取定时器时间,以及控制定时器开启的子函数


②:编写红外遥控模块IR
#include <REGX52.H>#include "Timer0.h"#include "Int0.h"unsigned int IR_Time;unsigned char IR_State;unsigned char IR_Data[4]; //数据缓存器unsigned char IR_pData; //指向存储的位置unsigned char IR_DataFlag;unsigned char IR_RepeatFlag;unsigned char IR_Address;unsigned char IR_Command;void Int0_Routine(void) interrupt 0{ if(IR_State==0) { Timer0_SetCounter(0); Timer0_Run(1); IR_State=1; } else if(IR_State==1) { IR_Time=Timer0_GetCounter(); Timer0_SetCounter(0); if(IR_Time>12442-500 && IR_Time<12442+500) //根据时间来判断是否是start信号 { IR_State=2; } else if(IR_Time>10368-500 && IR_Time<10368+500) //判断是否是repeat信号 { IR_RepeatFlag=1; Timer0_Run(0); IR_State=0; } else //其它未知的出错情况 { IR_State=1; } } else if(IR_State==2) { IR_Time=Timer0_GetCounter(); Timer0_SetCounter(0); if(IR_Time >1032-500 && IR_Time<1032+500) { IR_Data[IR_pData/8]&=~(0x01<<(IR_pData%8)); IR_pData++; } else if(IR_Time >2074-500 && IR_Time<2074+500) { IR_Data[IR_pData/8]|=(0x01<<(IR_pData%8)); IR_pData++; } else { IR_pData=0; IR_State=1; } if(IR_pData>=32) { IR_pData=0; if((IR_Data[0]==~IR_Data[1]) && (IR_Data[2]==~IR_Data[3]) ) { IR_DataFlag=1; IR_Address=IR_Data[0]; IR_Command=IR_Data[2]; } Timer0_Run(0); IR_State=0; } }}

③:编写main
#include <REGX52.H>#include "Delay.h"#include "LCD1602.h"#include "Int0.h"#include "IR.h"unsigned char Num;unsigned char Address;unsigned char Command;void main(){ LCD_Init(); IR_Init(); LCD_ShowString(1,1,"ADDR CMD NUM"); LCD_ShowString(2,1,"00 00 000"); while(1) { if(IR_GetDataFlag() || IR_GetRepeatFlag()) //可实现连加连减功能 { Address=IR_GetAddress(); Command=IR_GetCommand(); LCD_ShowHexNum(2,1,Address,2); LCD_ShowHexNum(2,7,Command,2); if(Command==IR_VOL_MINUS) { Num--; } if(Command==IR_VOL_ADD) { Num++; } LCD_ShowNum(2,12,Num,3); } }}
2.红外遥控控制电机调速
①:改造电机调速的文件
②:因为按键和红外遥控都用了定时器0,因此我们先把原本按键的定时器0改为定时器1
main函数部分做对应调整
③:Motor模块封装


④:加入红外模块,改造main函数











#include <REGX52.H>#include "Timer0.h"#include "Int0.h"unsigned int IR_Time;unsigned char IR_State;unsigned char IR_Data[4]; //数据缓存器unsigned char IR_pData; //指向存储的位置unsigned char IR_DataFlag;unsigned char IR_RepeatFlag;unsigned char IR_Address;unsigned char IR_Command;void Int0_Routine(void) interrupt 0{ if(IR_State==0) { Timer0_SetCounter(0); Timer0_Run(1); IR_State=1; } else if(IR_State==1) { IR_Time=Timer0_GetCounter(); Timer0_SetCounter(0); if(IR_Time>12442-500 && IR_Time<12442+500) //根据时间来判断是否是start信号 { IR_State=2; } else if(IR_Time>10368-500 && IR_Time<10368+500) //判断是否是repeat信号 { IR_RepeatFlag=1; Timer0_Run(0); IR_State=0; } else //其它未知的出错情况 { IR_State=1; } } else if(IR_State==2) { IR_Time=Timer0_GetCounter(); Timer0_SetCounter(0); if(IR_Time >1032-500 && IR_Time<1032+500) { IR_Data[IR_pData/8]&=~(0x01<<(IR_pData%8)); IR_pData++; } else if(IR_Time >2074-500 && IR_Time<2074+500) { IR_Data[IR_pData/8]|=(0x01<<(IR_pData%8)); IR_pData++; } else { IR_pData=0; IR_State=1; } if(IR_pData>=32) { IR_pData=0; if((IR_Data[0]==~IR_Data[1]) && (IR_Data[2]==~IR_Data[3]) ) { IR_DataFlag=1; IR_Address=IR_Data[0]; IR_Command=IR_Data[2]; } Timer0_Run(0); IR_State=0; } }}

#include <REGX52.H>#include "Delay.h"#include "LCD1602.h"#include "Int0.h"#include "IR.h"unsigned char Num;unsigned char Address;unsigned char Command;void main(){ LCD_Init(); IR_Init(); LCD_ShowString(1,1,"ADDR CMD NUM"); LCD_ShowString(2,1,"00 00 000"); while(1) { if(IR_GetDataFlag() || IR_GetRepeatFlag()) //可实现连加连减功能 { Address=IR_GetAddress(); Command=IR_GetCommand(); LCD_ShowHexNum(2,1,Address,2); LCD_ShowHexNum(2,7,Command,2); if(Command==IR_VOL_MINUS) { Num--; } if(Command==IR_VOL_ADD) { Num++; } LCD_ShowNum(2,12,Num,3); } }}




4.单总线介绍
①:介绍
②:时序结构
5.DS18B20操作流程
本节需要的指令SKIP ROM,CONVERT T:让温度转换器进行数据的转换,READ SCRATCHPAD:读暂存器,依次读出每一个字节。
SBUF:收发数据后,会产生相应的TI(发送中断)/RI(接收中断),继而进入中断函数,进行相应的中断函数内部的操作。
4) 定义一下各个寄存器的地址,方便操作;再定义一个存储时间的数组;
5) 编写DS1302的另外两个子函数——①:设定时间 ②:读出时间 并声明为外部可调用的函数和数组;
6) 编写主函数,调用函数在LCD显示屏上显示时间
2.功能化时钟——可以用独立按键设置要显示的时间
1)需要用到的模块
DS1302模块,LCD1602模块,独立按键key模块,定时器Timer0模块,延时函数模块;
2)编写主函数
主要分为四大部分:时钟模式选择,显示时间,设置时间(选择设置的时间位置,调整时间大小,利用定时器中断去实现选择的时间的位置的动态显示),更新显示新的时钟。
②:-表示时长,如图中的665-,其中5占两个节拍,
③:音符
一般以四分音符为一个基准
④:音符频率对照
⑤:以a440hz为基准,到另一个a,中间等比12频分,
⑥:单片机晶振芯片每秒震荡的次数称为时钟频率,震荡一次所需时间称为振荡周期。随机存储器ROM、
4) 编写LED矩阵显示的子函数
5) 自己设计图形,调用函数输入数据,即可显示;
示例代码2-点阵屏显示动画
1)把示例1的代码模块化
2)定义要显示的动画的数组,并初步检测是否显示正常
3)实现动态显示
上述代码实现的是流水式的动画,也可以改变offset去实现逐帧动画。
2) 进行位声明,方便操作。
②:OneWire模块编写
③:DS18B20模块编写
④:main函数
实例代码2-DS18B20温度报警器
①:要用到的模块:AT24C02,Delay,DS18B20,LCD1602,OneWire,I2C,key,Timer0
②:main函数
#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。
14-1 LCD1602液晶显示屏
1.介绍
2.引脚及应用电路
3.内部结构框图
4.存储器结构
5.时序结构
6.LCD1602指令集
7.LCD1602操作流程
14-2 功能代码编写
之后可以在main函数里调用流动的指令,实现流动字幕
15-1 直流电机
1.介绍
2.电机驱动电路
大功率器件直接驱动:只能使电机朝着一个方向转,不具备调换电机正反方向的功能。体积小、单片机基础介绍
1.何为单片机
单片机,英文Micro Controller Unit,简称MCU 。因此,我们接下来要学习,如何通过单总线来发送数据和接收数据。RI发送完置1(硬件只负责),但必须软件复位置0;
故SCON=0x40
PCON
4)配置定时器
这里定时器1,没有定时器0,所有要把高位修改(不影响高低位配置用“”& |“”这两个方式)
选择8位自动重载模式
5)可以直接用STC-isp来配置串口
系统频率根据板子选择,波特率4800,波特率发生器选择8位自动重载,时钟12T
6)发送数据的函数
7)发送单项数据
8)模块化
9)数据显示模式
8-3.串口实例实现
1)每一秒发送一个递增的数字
2)电脑通过串口控制LED灯,并且返回电脑读入的数据
1.需要打开串口的中断功能
SCON = 0x50; EA=1;ES=1;
注:要分清这里是禁止了定时器1的中断功能,只是让它的溢出率去开启串口收发的功能,中断的产生是由于串口收发数据产生的中断。
②电平标准
差分信号优点:传送距离远(1km+) TTL与RS232(10m)
③常见通信接口比较
CAN总线:常用于汽车领域,因为使用的是差分信号传输,传输距离远、12个震荡周期是一个机器周期,机器频率=晶振频率/12,计时周期=1/机器周期,即每过一个计时周期,定时器计数+1;
给定时器的TL和TH赋重装载值,使定时器每过所需周期的一半时计数+1(因为需要给震荡信号,故计数周期=原周期的二分之一),从而使蜂鸣器发出对应频率的声音。流水灯plus#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>#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); }}
通过任意延时函数去简化步骤
3-1、的代码复制到工程目录下,导入;2.主函数包含其他模块头文件并初始化;
3.复制定时器中断函数到main函数下:
4.定义变量,秒计数、下面的为共阳极(可以理解为3,8管脚处为供电,三角形尖尖有一横的是负极,所有共阴极),两个图中的数字为引脚:
4.下面为多个数码管,PCB板的4个为一体,同样上面为共阴极、
6.BCD码
10-2 实例代码
1.时钟
1)创建工程,cvLCD1602的文件,并开始模块化编写DS1302的模块
2) DS1302模块的子函数编写
3)初步测试
结果会发现,数字到9后会直接到16……,这是因为寄存器数据是以BCD码存储的,只需将Second改为Second/16*10+Second%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闪烁
2-3、
10-1 DS1302实时时钟介绍
1.介绍
定时器计时的缺点:1.精度不高 2.消耗单片机的CPU 3.断电不能继续计时
而时钟芯片精度高,且有备用电源,掉电可以用备用电源继续计时。延迟、稳定。分、用独立按键控制led灯移位
#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);}} }
4-1 静态数码管
1.常见数码管
2.控制数码管显示的原理图
3.管脚定义(对应字母控制对应位置亮):上面的为共阴极、LCD1602调试工具-------
1)调试工具原理图
2)模块化代码,下完放到自己工程目录下:
3)将下好的两个文件添加到工程:
4)文件主要内容如下:
5)main函数调用:
6)显示其他管脚冲突,所有会一起显示:
7)其他函数的调用及功能,可以设置显示位置和范围:
8)需要用到延迟函数:可以直接将前面模块化文件复制到工程目录下,添加进来引用即可;
9)娱乐:小计时器
#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); }//计时器
6-1.矩阵键盘
1)基础介绍:
P14-P17给0就代表扫描,其他给1(没选中),一次只能扫描一行;P10-P13给0表示按下,给1表示没按下;(逐列扫描)
2.代码实现:
①:创建工程并把“Delay”与“LCD1602”的模块加入此工程中。
单片机工作的基本时序
我们都知道在学校是通过铃声来控制所有班级的上下课时间,我们都知道单片机执行指令的过程就是从ROM取出一条指令执行来完成它在各个地方的作用,那它什么时候取指令这个是顺序呢?这里引入一个时序的周期,每访问一次ROM的时间,就是一个机器周期的时间。小时并显示:
5.代码综合
#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;} } } } }
8-1串口介绍
1)介绍
2)向单片机发送数据(下面框),返回(上框)
3)DB9串口传输数据(注意使用的电压是否一致)使用RS232或RS485电平
4)知识点
①硬件电路
注:最少需要三根线实现双向通信:TXD,RXD,GND。
2——秒表(用定时器扫描数码管)
①:先创建新的工程,包含所需的模块——独立按键,数码管,延迟函数,定时器,AT,I2C
②:改造独立按键模块——用定时器扫描独立按键
这样就不用像原来一样在检测时停在while死循环里,影响主函数进程
③:改造数码管模块——改造成用定时器扫描数码管
先在main模块的中断函数里加上一个计数定时器的T0Count2,这样每隔一段时间就会调用一下NixieLoop函数,而NixieLoop函数会不断扫描并在数码管上显示每一位数字。处理(依靠CPU)和硬件设备(例如电机,LED等)的控制 。
H桥驱动:可以控制电机正反转。