51单片机 定时器与串口通信
一、利用中断发出1Khz的方波信号,驱动蜂鸣器鸣叫
实验原理:
利用T1的中断控制P2.5引脚输出频率为1kHZ方波音频信号,驱动蜂鸣器发声。
Proteus实验原理图:
实验所需元器件名称如下:
C语言代码:
#include<reg51.h>
sbit sound=P2^5;
#define f1(a) (65536-a)/256
#define f2(a) (65536-a)%256
unsigned int i=500;
unsigned int j=0;
void t1 (void) interrupt 3 using 0
{
TR1=0;
sound=~sound;
TH1=f1(i);
TL1=f2(i);
j++;
TR1=1;
}
void main(void)
{
EA=1;
ET1=1;
TMOD=0X10;
TH1=f1(i);
TL1=f2(i);
TR1=1;
while(1)
{
i=460;
while(j<2000);
j=0;
i=360;
while(j<2000);
j=0;
}
}
开发板仿真效果图:
由于动态图的限制,所以无法听见蜂鸣器鸣叫声。
二、LED数码管秒表的制作
实验原理:
用2位数码管显示计时时间,最小计时单位为“百毫秒”,计时范围0.1~9.9s。当第1次按一下计时功能键时,秒表开始计时并显示;第2次按一下计时功能键时,停止计时,将计时的时间值送到数码管显示;如果计时到9.9s,将重新开始从0计时;第3次按一下计时功能键,秒表清0。再次按一下计时功能键,则重复上述计时过程。
Proteus原理图:
C语言代码:
#include<reg51.h>
typedef unsigned int uint; //定义无符号整形和字符型
typedef unsigned char uchar;
uchar led[] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90}; //共阳数码管 0 - 9
uchar led1[] = {0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10}; //共阳数码管 0 - 9 加小数点
uchar second; //秒数
uchar key; //按键次数
uint t; //用来计数,每500,代表0.1s
sbit keyif = P3^7; //按键接口
void delay(){ //延时函数,用于消除抖动
uchar i,j;
for(i=0;i<255;i++){
for(j=0;j<100;j++);
}
}
void init(void) //初始化
{
TMOD = 0x02; //0000 0010 使用方式二
second = 0; //秒数初始化为0
EA = 1; //总中断,定时器0中断允许
ET0 = 1; //允许定时器0中断
key = 0; //按键次数初始化为0
t = 0; //计数初始化为0
}
void main(){
init();
P0 = led1[second/10];
P2 = led[second%10];
while(1){
if(keyif == 0){
delay();//消除抖动
if(keyif == 0){
key++;
switch(key){
case 1: //按一次,计时器开始
TH0 = 0x38;
TL0 = 0x38; //200us,也就是0.2ms
TR0 = 1;
break;
case 2: //按两次,暂停定时器
t = 0;
TR0 = 0;
break;
case 3: //按三次,停止计时,数据清零
key = 0;
second = 0;
P0 = led1[0];
P2 = led[0];
break;
}
while(keyif == 0); //若一直按下,使其停留
}
}
}
}
void timer() interrupt 1
{
TR0 = 0; //停止计时
t++;
if(t == 500){
second++;
P0 = led1[second/10];
P2 = led[second%10];
t = 0;
}
if(second == 99){ //当计数到9.9秒,重新开始计时
second = 0;
key = 1; //相当于重新开始计时
}
TR0 = 1; //继续启动计时器
}
Proteus仿真效果图:
开发板效果图:
三、使用定时器实现一个LCD显示时钟
Proteus原理图:
C语言代码:
#include<reg51.h>
#include<lcd1602.h>
#define uchar unsigned char
#define uint unsigned int
uchar int_time; //定义中断次数计数变量
uchar second; //秒计数变量
uchar minute; //分钟计数变量
uchar hour; //小时计数变量
uchar code date[]="H.I.T.CHINA "; //LCD第1行显示的内容
uchar code time[]="TIME 23:59:55 "; //LCD第2行显示的内容
uchar second=55,minute=59,hour=23;
void clock_init()
{
uchar i,j;
for(i=0;i<16;i++)
{
write_data(date[i]);
}
write_com(0x80+0x40);
for(j=0;j<16;j++)
{
write_data(time]);
}
}
void clock_write( uint s, uint m, uint h)
{
write_sfm(0x47,h);
write_sfm(0x4a,m);
write_sfm(0x4d,s);
}
void main()
{
init1602(); //LCD初始化
clock_init(); //时钟初始化
TMOD=0x01; //设置定时器TO为方式1定时
EA=1; //总中断开
ET0=1; //允许TO中断
TH0=(65536-46483)/256; //给TO装初值
TLO=(65536-46483)%256;
TR0=1;
int_time=0;
中断次数、秒、分、时单元清0
second=55;
minute=59;hour=23;
{while(1)
clock_write(second ,minute, hour);
}
}
void T0_interserve(void) interrupt 1 using 1
lITO中断服务子程序
{
int_time++; //中断次数加1
if(int_time==20) //若中断次数计满20次
{
int_time=0; //中断次数变量清0
second++; //秒计数变量加1
}
if(second==60) //若计满60s
{
second=0; //秒计数变量清0
minute ++; //分计数变量加1
}
if(minute==60)
I若计满60分
{
minute=0; //分计数变量清0
hour ++; //小时计数变量加1
}
if(hour==24)
{
hour=0; //小时计数计满24,将小时计数变量清0
}
TH0=(65536-46083)/256; //定时器T0重新赋值
TL0=(65536-46083)%256;
}
由于代码头文件目录原因,本人未能生成.hex文件,所以就不展示效果图了,望理解。。。。
四、串口通信
1、串口通信原理
串口通信是一种通过串行通信接口进行数据传输的方式。串口通信通常使用RS-232标准来定义数据传输的格式和电气特性。
串口通信的原理包括以下几个方面:
-
数据传输格式:串口通信使用一定的数据传输格式来定义数据的结构和传输方式。通常包括数据位数、校验位、停止位等参数。
-
波特率:波特率是串口通信中一个重要的参数,用来表示每秒钟传输的比特数。波特率越高,数据传输速度越快。
-
串口控制信号:串口通信中还包括一些控制信号,用来控制数据的传输和接收。例如,RTS(请求发送)、CTS(清除发送)、DTR(数据终端就绪)等信号。
-
数据传输流程:串口通信的数据传输流程通常包括发送端发送数据、接收端接收数据、校验数据的完整性等步骤。
-
数据传输协议:在串口通信中,通常需要定义一定的数据传输协议来保证数据的正确传输和接收。常见的协议包括ASCII码、Modbus等。
总的来说,串口通信是一种简单而可靠的数据传输方式,广泛应用于各种设备和系统中。通过了解串口通信的原理,可以更好地理解和应用串口通信技术。
2、甲乙两个单片机串口通信
Proteus原理图:
C语言代码:
A机发送端:
#include <reg51.h>
sbit p=PSW^0; //P位为PSW寄存器的第0位,即奇偶校验位
unsigned char Tab[8]= {0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f}; //控制流水灯显示数据数组,为全局变量
void Send(unsigned char dat) //发送1字节数据的函数
{
TB8=p; //将偶校验位作为第9位数据发送
SBUF=dat;
while(TI==0); //检测TI,TI=0,未发送完
; //空操作
TI=0; // 1字节发送完,TI清0
}
void delay (void) //延时约200ms的函数
{
unsigned char m,n;
for(m=0;m<250;m++)
for(n=0;n<250;n++) ;
}
void main(void) //主函数
{
unsigned char i ;
TMOD=0x20; //设置定时器T1为方式2
SCON=0xc0; //设置串口为方式3
PCON=0x00; //SMOD=0
TH1=0xfd; //给T1赋初值,波特率设置为9600
TL1=0xfd;
TR1=1; //启动定时器T1
while(1)
{
for(i=0;i<8;i++)
{
Send (Tab[i]);
delay() ; //大约200ms发送一次数据
}
}
}
B机接收端:
#include <reg51.h>
sbit p=PSW^0; //P位为PSW寄存器的第0位,即奇偶校验位
unsigned char Receive(void) //接收1字节数据的函数
{
unsigned char dat;
while(RI==0) ; //检测RI,RI=0,未接收完,则循环等待;
;
RI=0; //己接收一帧数据,将RI清0
ACC=SBUF; //将接收缓冲器的数据存于ACC
if(RB8==p) //只有偶校验成功才能往下执行,接收数据
{
dat=ACC; //将接收缓冲器的数据存于dat
return dat; //将接收的数据返回
}
}
void main(void) //主函数
{
TMOD=0x20; //设置定时器T1为方式2
SCON=0xd0; //设置串口为方式3,允许接收REN=1
PCON=0x00; // SMOD=0
TH1=0xfd; //给定时器T1赋初值,波特率为9600
TL1=0xfd;
TR1=1; //接通定时器T1
REN=1; //允许接收
while(1)
{
P1= Receive( ); //将接收到的数据送P1口显示
}
}
Proteus仿真效果图:
五、Hello C51
实验原理:
将单片机串口与笔记本电脑串口模块相连,单片机每隔2秒发送“Hello C51”,笔记本电脑用串口助手软件接收。 如果串口助手发送字符“0" 给单片机,则单片机停止发送; 如果单片机收到“1”,则继续每隔2秒发送“Hello C51”。
代码:
#include<reg51.h>
#define uint unsigned int
#define uchar unsigned char
uint p=0;//??????0
void delay_2s()//????
{
int i,j;
for(i=0;i<21800;i++)
{
for(j=10;j>0;j--);
}
}
void uart_sendbyte(uchar byte)//????
{
SBUF=byte;
while(TI==0);
TI=0;
}
void helloc51()
{
uart_sendbyte('h');
uart_sendbyte('e');
uart_sendbyte('l');
uart_sendbyte('l');
uart_sendbyte('o');
uart_sendbyte('c');
uart_sendbyte('5');
uart_sendbyte('1');
uart_sendbyte(' ');
}
void uart_init(uchar baud)//uart???
{
TMOD|=0X20;
SCON=0X50;
PCON=0X80;
TH1=baud;
TL1=baud;
ES=1;
EA=1;
TR1=1;
}
void uart() interrupt 4
{
if(RI==1)//?????????
{
uchar rec_data;
rec_data=SBUF;
RI=0;
if(rec_data==0)//??0,?????0
{
p=0;
}
else if(rec_data==1)
{
p=1;
}
}
}
void main()
{
uart_init(0XFA);
while(1)
{
if(p==0)//??0,????
{
while(p==0)
{
}
}
else if(p==1)//??1,????hello c51????2s
{
while(p==1)
{
helloc51();
delay_2s();
}
}
}
}
将PZ中波特率调整到9600,奇偶位调至even,校验方式改为LRC,发送区改为HEX发送即可,在发送区发送00、01即可完成实验,实验效果如下:
作者:Yu_