[51单片机]单片机定时器与串口通信-程序员宅基地

技术标签: 51单片机  嵌入式硬件  单片机  

目录

1、利用中断发出1Khz的方波信号,驱动蜂鸣器鸣叫。

实验原理图

 c语言代码

实验结果

2、LED数码管秒表的制作。

原理电路

程序代码

运行结果 

 ​编辑

3、使用定时器实现一个LCD显示时钟。

原理电路

C语言程序

实验结果 

4、甲乙两个单片机串口通信

实验原理图

c程序

甲机发送程序

乙机接收程序

实验结果

 ​编辑

5、将单片机串口与笔记本电脑串口模块相连,单片机每隔2秒发送“Hello C51”.

实验代码

实验结果

 总结


1、利用中断发出1Khz的方波信号,驱动蜂鸣器鸣叫。

利用T1的中断控制P1.7引脚输出频率为1kHz方波音频信号,驱动蜂鸣器发声。系统时钟为12MHz。方波音频信号周期1ms,因此T1的定时中断时间为0.5 ms,进入中断服务程序后,对P1.7求反.

先计算T1初值,系统时钟为12MHz,则机器周期为1µs。1kHz音频信号周期为1ms,要定时计数的脉冲数为a。则T1初值:                  

TH1=(65 536 −a) /256;              

TL1=(65 536 −a) %256.

实验原理图

 c语言代码

#include<reg51.h>  			//包含头文件
sbit sound=P1^7;  			//将sound位定义为P1.7脚
#define f1(a) (65536-a)/256		//定义装入定时器高8位时间常数
#define f2(a) (65536-a)%256    		//定义装入定时器低8位时间常数
unsigned int i=500; 
unsigned int j=0; 
void main(void)
{
	 	EA=1;                  		//开总中断.
  		ET1=1;                		//允许定时器T1中断         .
   		TMOD=0x10; 			//TMOD=0001 000B,使用T1的方式1定时    	TH1=f1(i);      			//给T1高8位赋初值.
   		TL1=f2(i);      			//给T1低8位赋初值.
   		TR1=1;                 		//启动T1
   		while(1)  
{              				//循环等待
     	i=460; 
      	while(j<2000);
      	j=0;
      	i=360; 
      	while(j<2000);
      	j=0;
    }
 }

void T1(void) interrupt 3 using 0	//定时器T1中断函数
{
    	TR1= 0;                 	//关闭T1
   	sound=~sound; 			//P1.7输出求反
    	TH1=f1(i);   			//T1的高8位重新赋初值.
    	TL1=f2(i);   			//T1的低8位重新赋初值.
j++;				
    	TR1=1;                 	//启动定时器T1
}

实验结果

 

2、LED数码管秒表的制作。

用2位数码管显示计时时间,最小计时单位为“百毫秒”,计时范围0.1~9.9s。当第1次按一下计时功能键时,秒表开始计时并显示;第2次按一下计时功能键时,停止计时,将计时的时间值送到数码管显示;如果计时到9.9s,将重新开始从0计时;第3次按一下计时功能键,秒表清0。再次按一下计时功能键,则重复上述计时过程。

用2位数码管显示计时时间,最小计时单位为“百毫秒”,计时范围0.1~9.9s。当第1次按一下计时功能键时,秒表开始计时并显示;第2次按一下计时功能键时,停止计时,将计时的时间值送到数码管显示;如果计时到9.9s,将重新开始从0计时;第3次按一下计时功能键,秒表清0。再次按一下计时功能键,则重复上述计时过程.本秒表应用定时器模式,计时范围0.1~9.9s。此外还涉及如何编写控制LED数码管显示的程序。    

原理电路

程序代码

#include<reg51.h>  			//头文件
unsigned char code discode1[]=                                  			{0xbf,0x86,0xdb,0xcf,0xe6,0xed,0xfd,0x87,0xff,0xef};	
                             	//数码管显示0~9的段码表, 带小数点
unsigned char code discode2[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};	
                            	//数码管显示0~9的段码表,不带小数点
unsigned char timer=0;		//timer记录中断次数
unsigned char second;        	//second储存秒
unsigned char key=0;		//key记录按键次数

main()				//主函数
{
	 TMOD=0x01;			//定时器T0方式1定时
	 ET0=1;                   	//允许定时器T0中断
EA=1;                    		//总中断允许
second=0;                		//设初始值
P0=discode1[second/10];   		//显示秒位0
P2=discode2[second%10];   		//显示0.1s位0
while(1)				 //循环
{	
	if((P3&0x80)==0x00)		//当按键被按下时
	{	 
		key++;			//按键次数加1
		switch(key)		//根据按键次数分三种情况
		{
			case 1:		//第一次按下为启动秒表计时
			TH0=0xee; 	//向TH0写入初值的高8位
TL0=0x00;	   	//向TL0写入初值的低8位,定时5ms
	TR0=1;         		//启动定时器T0
	break;
	case 2:        		//按下两次暂定秒表
	TR0=0;         		//关闭定时器T0
	break;
	case 3:        			//按下3次秒表清0
	key=0;         			//按键次数清
	second=0;      			//秒表清0
	P0=discode1[second/10];   	//显示秒位0   				P2=discode2[second%10];  	//显示0.1s位0
	break;
}
while((P3&0x80)==0x00);     		//如果按键时间过长在此循环
}
}
}
void int_T0() interrupt 1  using 0 		//定时器T0中断函数
{						
	TR0=0;		 	//停止计时,执行以下操作(会带来计时误差)
	TH0=0xee;	  	//向TH0写入初值的高8位
	TL0=0x00;	   	//向TL0写入初值的低8位,定时5ms
	timer++;   	   	//记录中断次数
	if (timer==20)	   	//中断20次,共计时20*5ms=100ms=0.1s
	{
		timer=0;    			//中断次数清0
		second++;   			//加0.1s
		P0=discode1[second/10]; 	//根据计时,即时显示秒位		
        P2=discode2[second%10]; 	//根据计时,即时显示0.1s位	
 }
if(second==99) 		 //当计时到9.9s时
{
	TR0=0;			//停止计时
	second=0;		//秒数清0		
	key=2;	  		//按键数置2,当再次按下按键时,					//key++,即key=3,秒表清0复原	
}                           
else				//计时不到9.9s时
{
	TR0=1;			//启动定时器继续计时
}
}

运行结果 

 

3、使用定时器实现一个LCD显示时钟。

使用定时器实现一个LCD显示时钟。采用LCD1602.

最小计时单位是秒,如何获得1s的定时?

可将T0定时时间定为50ms,采用中断方式进行溢出次数累计,满20次,则秒计数变量second加1;若秒计满60,则分计数变量minute加1,同时将秒计数变量second清0;若分钟计满60,则小时计数变量hour加1;若小时计数变量满24,则将小时计数变量hour清0。

原理电路

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[j]);
	}
}

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;			 //设置定时器T0为方式1定时
EA=1;            			// 总中断开 
ET0=1; 				// 允许T0中断 
TH0=(65536-46483)/256;	//给T0装初值
TL0=(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 	//T0中断服务子程序
{	
	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)			//若计满60分
{ 	
	minute=0;		//分计数变量清0
	hour ++;		//小时计数变量加1
}
if(hour==24)
{ 	
	hour=0;			//小时计数计满24,将小时计数变量清0
}
TH0=(65536-46083)/256;		//定时器T0重新赋值
TL0=(65536-46083)%256;
}

先将定时器以及各计数变量设定完毕,然后调用时间显示子程序。秒计时由T0中断服务子程序来实现。

执行上述程序仿真运行,就会在LCD上显示实时时间。

实验结果 

4、甲乙两个单片机串口通信

在实物实验时,如果不能找到两个普中单片机,用笔记本电脑的串口助手程序代替其中一个单片机,实现课件上描述的主要功能。

甲、乙两单片机进行 方式3(或方式2)串行通信。甲机把控制8个流水灯点亮的数据发送给乙机并点亮其P1口的8个LED。方式3比方式1多了1个可编程位TB8,该位一般作奇偶校验位。乙机接收到的8位二进制数据有可能出错,需进行奇偶校验,其方法是将乙机的RB8和PSW的奇偶校验位P进行比较,如果相同,接收数据;否则拒绝接收。

我们使用了一个虚拟终端来观察甲机串口发出的数据。

实验原理图

c程序

甲机发送程序

#include <reg51.h>
  sbit P=PSW^0;		//P位为PSW寄存器的第0位,即奇偶校验位
  unsigned char Tab[8]= {0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf,  
                  0xbf, 0x7f};   //控制流水灯显示数据数组,为全局变量

 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发送一次数据
      }
  }
  }
  
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++);
  } 

乙机接收程序

#include <reg51.h>
  sbit P=PSW^0;		// P位为PSW 寄存器的第0位,即奇偶校验位
  
  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口显示
  }
  }
  
    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;		//将接收的数据返回
  }
  }    

实验结果

 

5、将单片机串口与笔记本电脑串口模块相连,单片机每隔2秒发送“Hello C51”.

笔记本电脑用串口助手软件接收。 如果串口助手发送字符“0" 给单片机,则单片机停止发送; 如果单片机收到“1”,则继续每隔2秒发送“Hello C51”。

实验代码

#include <REGX52.H>
#include "stdio.h"
unsigned char ch;
unsigned char Flag=1;
void Delay(unsigned int xms)		//@11.0592MHz
{
	unsigned char i, j;
 
	while(xms--)
	{
		i = 2;
		j = 199;
		do
		{
			while (--j);
		} while (--i);
	}
}
 
void UartInit(void)		
{
	PCON &= 0x7F;		
	SCON = 0x50;		
	TMOD &= 0x0F;		
	TMOD |= 0x20;		
	TL1 = 0xFD;		
	TH1 = 0xFD;		
	ET1 = 0;		
	TR1 = 1;		
	EA=1;
	ES=1;
}
void UartSend()
{
		TI=1;
		puts("Hello C51");
		while(!TI);
		TI=0;
		Delay(2000);
}
 
void main()
{
	UartInit();
	while(1)
	{
		if(Flag==1)UartSend();
	}	
}
 
 
void UART_Routine()	interrupt 4 
{
	if(RI==1)
	{
		RI=0;
		ch=SBUF;
		if(ch=='1')Flag=1;
		if(ch=='0')Flag=0;
	}
}

实验结果

发送0,:

发送“1”,则继续每隔2秒发送“Hello C51”:

 总结

通过此次学习51单片机单片机定时器与串口通信的相关内容,掌握了单片机定时器与串口通信的使用方法,了解了如何利用单片机定时器与串口来实现对外部事件的实时控制,还学习了单片机定时器与串口的工作原理和编程方法,掌握了如何利用定时器来实现时间精确控制,提高了系统的时间管理能力。

了解了单片机定时器与串口的工作机制,学会了合理设置定时器的工作参数,从而能够有效地节省系统资源,提高系统的性能和效率。

通过实际的应用案例,如LED数码管秒表的制作、使用定时器实现一个LCD显示时钟等,将理论知识与实际操作相结合,加深了对单片机定时器与串口通信的理解和掌握。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/abcdxymsj/article/details/137958590

智能推荐

使用nginx解决浏览器跨域问题_nginx不停的xhr-程序员宅基地

文章浏览阅读1k次。通过使用ajax方法跨域请求是浏览器所不允许的,浏览器出于安全考虑是禁止的。警告信息如下:不过jQuery对跨域问题也有解决方案,使用jsonp的方式解决,方法如下:$.ajax({ async:false, url: 'http://www.mysite.com/demo.do', // 跨域URL ty..._nginx不停的xhr

在 Oracle 中配置 extproc 以访问 ST_Geometry-程序员宅基地

文章浏览阅读2k次。关于在 Oracle 中配置 extproc 以访问 ST_Geometry,也就是我们所说的 使用空间SQL 的方法,官方文档链接如下。http://desktop.arcgis.com/zh-cn/arcmap/latest/manage-data/gdbs-in-oracle/configure-oracle-extproc.htm其实简单总结一下,主要就分为以下几个步骤。..._extproc

Linux C++ gbk转为utf-8_linux c++ gbk->utf8-程序员宅基地

文章浏览阅读1.5w次。linux下没有上面的两个函数,需要使用函数 mbstowcs和wcstombsmbstowcs将多字节编码转换为宽字节编码wcstombs将宽字节编码转换为多字节编码这两个函数,转换过程中受到系统编码类型的影响,需要通过设置来设定转换前和转换后的编码类型。通过函数setlocale进行系统编码的设置。linux下输入命名locale -a查看系统支持的编码_linux c++ gbk->utf8

IMP-00009: 导出文件异常结束-程序员宅基地

文章浏览阅读750次。今天准备从生产库向测试库进行数据导入,结果在imp导入的时候遇到“ IMP-00009:导出文件异常结束” 错误,google一下,发现可能有如下原因导致imp的数据太大,没有写buffer和commit两个数据库字符集不同从低版本exp的dmp文件,向高版本imp导出的dmp文件出错传输dmp文件时,文件损坏解决办法:imp时指定..._imp-00009导出文件异常结束

python程序员需要深入掌握的技能_Python用数据说明程序员需要掌握的技能-程序员宅基地

文章浏览阅读143次。当下是一个大数据的时代,各个行业都离不开数据的支持。因此,网络爬虫就应运而生。网络爬虫当下最为火热的是Python,Python开发爬虫相对简单,而且功能库相当完善,力压众多开发语言。本次教程我们爬取前程无忧的招聘信息来分析Python程序员需要掌握那些编程技术。首先在谷歌浏览器打开前程无忧的首页,按F12打开浏览器的开发者工具。浏览器开发者工具是用于捕捉网站的请求信息,通过分析请求信息可以了解请..._初级python程序员能力要求

Spring @Service生成bean名称的规则(当类的名字是以两个或以上的大写字母开头的话,bean的名字会与类名保持一致)_@service beanname-程序员宅基地

文章浏览阅读7.6k次,点赞2次,收藏6次。@Service标注的bean,类名:ABDemoService查看源码后发现,原来是经过一个特殊处理:当类的名字是以两个或以上的大写字母开头的话,bean的名字会与类名保持一致public class AnnotationBeanNameGenerator implements BeanNameGenerator { private static final String C..._@service beanname

随便推点

二叉树的各种创建方法_二叉树的建立-程序员宅基地

文章浏览阅读6.9w次,点赞73次,收藏463次。1.前序创建#include&lt;stdio.h&gt;#include&lt;string.h&gt;#include&lt;stdlib.h&gt;#include&lt;malloc.h&gt;#include&lt;iostream&gt;#include&lt;stack&gt;#include&lt;queue&gt;using namespace std;typed_二叉树的建立

解决asp.net导出excel时中文文件名乱码_asp.net utf8 导出中文字符乱码-程序员宅基地

文章浏览阅读7.1k次。在Asp.net上使用Excel导出功能,如果文件名出现中文,便会以乱码视之。 解决方法: fileName = HttpUtility.UrlEncode(fileName, System.Text.Encoding.UTF8);_asp.net utf8 导出中文字符乱码

笔记-编译原理-实验一-词法分析器设计_对pl/0作以下修改扩充。增加单词-程序员宅基地

文章浏览阅读2.1k次,点赞4次,收藏23次。第一次实验 词法分析实验报告设计思想词法分析的主要任务是根据文法的词汇表以及对应约定的编码进行一定的识别,找出文件中所有的合法的单词,并给出一定的信息作为最后的结果,用于后续语法分析程序的使用;本实验针对 PL/0 语言 的文法、词汇表编写一个词法分析程序,对于每个单词根据词汇表输出: (单词种类, 单词的值) 二元对。词汇表:种别编码单词符号助记符0beginb..._对pl/0作以下修改扩充。增加单词

android adb shell 权限,android adb shell权限被拒绝-程序员宅基地

文章浏览阅读773次。我在使用adb.exe时遇到了麻烦.我想使用与bash相同的adb.exe shell提示符,所以我决定更改默认的bash二进制文件(当然二进制文件是交叉编译的,一切都很完美)更改bash二进制文件遵循以下顺序> adb remount> adb push bash / system / bin /> adb shell> cd / system / bin> chm..._adb shell mv 权限

投影仪-相机标定_相机-投影仪标定-程序员宅基地

文章浏览阅读6.8k次,点赞12次,收藏125次。1. 单目相机标定引言相机标定已经研究多年,标定的算法可以分为基于摄影测量的标定和自标定。其中,应用最为广泛的还是张正友标定法。这是一种简单灵活、高鲁棒性、低成本的相机标定算法。仅需要一台相机和一块平面标定板构建相机标定系统,在标定过程中,相机拍摄多个角度下(至少两个角度,推荐10~20个角度)的标定板图像(相机和标定板都可以移动),即可对相机的内外参数进行标定。下面介绍张氏标定法(以下也这么称呼)的原理。原理相机模型和单应矩阵相机标定,就是对相机的内外参数进行计算的过程,从而得到物体到图像的投影_相机-投影仪标定

Wayland架构、渲染、硬件支持-程序员宅基地

文章浏览阅读2.2k次。文章目录Wayland 架构Wayland 渲染Wayland的 硬件支持简 述: 翻译一篇关于和 wayland 有关的技术文章, 其英文标题为Wayland Architecture .Wayland 架构若是想要更好的理解 Wayland 架构及其与 X (X11 or X Window System) 结构;一种很好的方法是将事件从输入设备就开始跟踪, 查看期间所有的屏幕上出现的变化。这就是我们现在对 X 的理解。 内核是从一个输入设备中获取一个事件,并通过 evdev 输入_wayland

推荐文章

热门文章

相关标签