51单片机 (6)串口中断通信+定时器2串口中断

【若有疑问错误或版权等问题请联系我】 

【转载请注明出处:http://blog.csdn.net/leytton/article/details/48442129

51单片机默认使用定时器1作为串口通信的波特率发生器、定时器1中断通信,串口与定时器1冲突,在遇到定时器不够用的时候可以用定时器2

#include <reg52.h>


void DelayMs(unsigned int i);
void SerialInit();
void SendByte(unsigned char sbyte);
void SendString(unsigned char *pstr);


void main(void)
{
		SerialInit();
		while(1);	  //注:必需要无限循环
}


/*
//单片机时钟周期:11.0592MHz   以时钟1作为波特率发生器
void SerialInit(){
 TMOD=0x20;   //设置T1工作方式为方式2
 TH1=0xfd; //给定时器高位装初值
 TL1=0xfd; //给定时器低位装初值
 TR1=1;  //开定时器
             //以上是设置波特率
 SM0=0;  //设置串口通讯方式为方式1
 SM1=1;  
 REN=1;  //串口是否接收数据的开关

 EA=1; //总中断打开,采用查询法时不用打开中断
 ES=1; //串口中断开关,采用查询法时不用打开中断
}
*/
//单片机时钟周期:11.0592MHz	   以时钟T2作为波特率发生器
void SerialInit(){
 	 PCON &= 0x7F;      //波特率不倍速 SMOD=0
     SCON = 0x50;       //方式1,8位数据,可变波特率,接收允许
     T2CON  = 0x34;   
     RCAP2H = 0xFF;    
     RCAP2L = 0xDC;  
     TH2    = 0xFF;  
     TL2    = 0xDC;
	   
	 EA=1; //总中断打开,采用查询法时不用打开中断 
     ES = 1;          //串口中断开关,采用查询法时不用打开中断

}


//串口中断函数:
void SerialPortInte(void) interrupt 4 //采用串口中断法收发数据
{
	 unsigned char rbyte;
	 if(RI){     //RI=1,判定为串口接收到了数据,RI要清零,
         RI=0;
		 rbyte=SBUF; 
		 if(rbyte==0x0A){ 	  
		    SendString("换行");
		 }else if(rbyte==0x0D){
		 	SendString("回车");
		 }else{
		 	SendByte(rbyte); 
		 }
		 	
     }

}

//串口发送一个字节:
void SendByte(unsigned char sbyte)
{ 
     SBUF=sbyte; //发送数据
     while(!TI); //等待发送完成
     TI=0; //清零发送标志位
}
 
//串口发送一个字符串:
void SendString(unsigned char *pstr) //定义指针
{
     while(*pstr!='\0') //字符串是否发完
     {
         SendByte(*pstr);//发送字符串数据
         pstr++; //指向下一个字符
     }
}

void DelayMs(unsigned int i)  //延时i ms
{
    unsigned int j;
    while(i--)
    {
        for(j = 0; j < 125; j++);
    }
}


  • 8
    点赞
  • 43
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
这个项目可以分为以下几个部分: 1. LCD1602的初始化和显示设置; 2. 定时器的初始化和计时功能; 3. 串口的初始化和数据接收; 4. 秒表功能的实现。 以下是基本的代码框架和说明: ```c #include <reg51.h> #include <stdio.h> #include <stdlib.h> #define LCD_RS P1_0 #define LCD_RW P1_1 #define LCD_EN P1_2 #define LCD_DATA P2 // LCD1602的命令和数据义 #define LCD_CMD_CLEAR 0x01 #define LCD_CMD_HOME 0x02 #define LCD_CMD_ENTRY_MODE 0x06 #define LCD_CMD_DISPLAY_ON_OFF 0x0C #define LCD_CMD_FUNCTION_SET 0x28 // 定时器的计数值 #define TIMER_VALUE 65536-50000 // 串口的波特率 #define BAUD_RATE 9600 // 全局变量 volatile unsigned int count = 0; // 函数声明 void lcd_init(); void lcd_cmd(unsigned char cmd); void lcd_data(unsigned char data); void lcd_display(unsigned char *str); void timer_init(); void timer_isr() interrupt 1; void uart_init(); void uart_isr() interrupt 4; void main() { unsigned char str[16] = {0}; unsigned char sec = 0; unsigned char min = 0; unsigned char hour = 0; unsigned char start = 0; lcd_init(); timer_init(); uart_init(); while (1) { // 从串口接收数据,判断是否开始计时 if (start == 0) { if (RI == 1) { RI = 0; if (SBUF == 's') { start = 1; } } } else { // 开始计时 if (count >= 20) { count = 0; sec++; if (sec == 60) { sec = 0; min++; if (min == 60) { min = 0; hour++; if (hour == 24) { hour = 0; } } } sprintf(str, "%02d:%02d:%02d", hour, min, sec); lcd_cmd(LCD_CMD_CLEAR); lcd_display(str); } } } } // LCD1602的初始化 void lcd_init() { lcd_cmd(LCD_CMD_FUNCTION_SET); lcd_cmd(LCD_CMD_DISPLAY_ON_OFF); lcd_cmd(LCD_CMD_CLEAR); lcd_cmd(LCD_CMD_ENTRY_MODE); } // 发送命令到LCD1602 void lcd_cmd(unsigned char cmd) { LCD_RS = 0; LCD_RW = 0; LCD_DATA = cmd; LCD_EN = 1; LCD_EN = 0; delay(1); } // 发送数据到LCD1602 void lcd_data(unsigned char data) { LCD_RS = 1; LCD_RW = 0; LCD_DATA = data; LCD_EN = 1; LCD_EN = 0; delay(1); } // 在LCD1602上显示字符串 void lcd_display(unsigned char *str) { while (*str) { lcd_data(*str++); } } // 定时器的初始化 void timer_init() { TMOD |= 0x10; TH1 = TH0 = TIMER_VALUE / 256; TL1 = TL0 = TIMER_VALUE % 256; TR1 = TR0 = 1; ET0 = 1; EA = 1; } // 定时器中断服务函数 void timer_isr() interrupt 1 { TH0 = TH1 = TIMER_VALUE / 256; TL0 = TL1 = TIMER_VALUE % 256; count++; } // 串口的初始化 void uart_init() { TMOD |= 0x20; TH1 = 256 - (11059200 / 12 / 32 / BAUD_RATE); TL1 = TH1; TR1 = 1; SM0 = 0; SM1 = 1; REN = 1; ES = 1; EA = 1; } // 串口中断服务函数 void uart_isr() interrupt 4 { if (RI == 1) { RI = 0; } } ``` 在上面的代码中,我们使用定时器串口两个中断服务函数,需要在主函数中开启总中断。同时,我们义了一个全局变量 `count` 来计数,每次定时器中断服务函数被调用时,`count` 就会加1。 在主函数中,我们先初始化 LCD1602、定时器串口,然后进入一个死循环。在循环中,我们从串口接收数据,如果接收到了 's' 字符,就开始计时,否则等待下一次接收。 当开始计时后,每次定时器中断服务函数被调用时,我们就将 `count` 加1,当 `count` 大于等于 20 时,就表示一秒钟过去了,我们将秒数加1,然后根据秒、分、时的值来更新 LCD1602 的显示。最后,我们使用 `lcd_cmd(LCD_CMD_CLEAR)` 来清屏,然后使用 `lcd_display(str)` 来显示时间字符串。 需要注意的是,定时器的计数值需要根据实际情况进行调整,以实现精确的计时功能。同时,由于串口中断服务函数中没有处理接收到的数据,因此需要在主函数中进行处理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值