蓝桥杯单片机——串口

1.概要 

1.实验名称:串口通讯实验
2.实验环境:IAP15F2K61S2国信长天实验板
3.实验配置:J13跳线配置为I/O模式,J5配置为BTN模式,J2配置为11-3,2-4模式,
            J6配置为蜂鸣器电源 
4.实验时间:2025-1-22

5.实验内容:PC与MCU进行串口通信,分别进行MCU向PC 循环发送内容和MUC与PC之间的收发实验

2.技术实现

        1.硬件环境

                IAP15F2K61S2单片机部分

由于硬件设计,仍需手动关闭LED和蜂鸣器

                74HC138译码器 

         74HC573锁存器

                 74HC02高速硅栅CMOS器件

        2.原理图 

        3.代码实现 

                        1.串口通讯

#include <STC15F2K60S2.h>
#include <intrins.h>

#define LED(X) {P2=((P2&0X1F)|0X80);P0=X;P2&=0X1F;}

#define BAUD 9600
#define SYSclk 11059200L

/*延时函数*/
void Delay1000ms(void)	//@11.0592MHz
{
	unsigned char data i, j, k;

	_nop_();
	_nop_();
	i = 43;
	j = 6;
	k = 203;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}
/*串口发送函数*/
void uart_sendstring(unsigned char *str)
{
    unsigned char *p;
    p = str;
    while(*p != '\0')
    {
        SBUF = *p;
        while(TI == 0);         //等待发送标志位置1
        TI = 0;
        p++;
    }
}

void close_buz()
{
    P2 = ((P2&0x1f) | 0xA0);
    P0 = 0X00;
    P2 &= 0X1F;
}

/*主函数*/
void main(void)
{
    LED(0XFF);                  //关闭LED  
    close_buz();                //关闭蜂鸣器
    SCON = 0x50;                //串行控制寄存器,8位数据。波特率可变
    AUXR = 0X40;                //辅助寄存器,定时器时钟1T模式
    TMOD &= 0x00;               //定时器/计时器工作模式寄存器,将定时器1设置为16位自动重载定时器
    TL1 = (65536 - (SYSclk / 4 / BAUD));
    TH1 = (65536 - (SYSclk / 4 / BAUD)) >> 8;
    TR1 = 1;                    //定时器1运行控制位
    while(1)
    {      
        uart_sendstring("\r\n");
        uart_sendstring("hello");
        uart_sendstring("\r\n");
        uart_sendstring("你好");
        Delay1000ms();
    }
    
}

MCU向PC发送数据,本实验中MCU向PC发送制表符换行符,然后发送hello,然后再发送制表符和换行符,然后发送“你好”。 

                        2.串口收发实验

#include <STC15F2K60S2.h>

#define BAUD 9600           //波特率
#define SYSclk 11059200L    //系统时钟频率    /*11059200L中L表示宏SYSclk的数据类型为long型*/

#define BUZ(X) {P0 = X;P2 = ((P2 & 0X1F) | 0XA0);P2 = P2 & 0x1f;}

bit Rx_flag = 0;            //数据接收标志位
char Rx_data = '1';         //接收到的数据
void uart_sendstring(unsigned char *str);
    
void main()
{   
    BUZ(0X00);              //关闭蜂鸣器
    SCON = 0X50;            //串行控制寄存器,8位UART,波特率可变
    /*
        设置定时器1为波特率发生器
    */
    AUXR = 0X40;            //辅助寄存器,定时器1时钟1T模式
    TMOD = 0X00;            //计时器/定时器工作模式寄存器,将定时器设置为模式0(16位自动重载)
    TL1 = (65536 - (SYSclk/4/BAUD));
    TH1 = (65536 - (SYSclk/4/BAUD))>>8;
    TR1 = 1;                //定时器1控制允许位
    ES = 1;                 //串口1中断允许位
    EA = 1;                 //总中断允许位
    
    while(1)
    {
        if(Rx_flag == 1)    //判断数据标志位
        {
            Rx_flag = 0;
            switch(Rx_data)
            {
                case '1':
                {
                    P2 = ((P2 & 0x1f) | 0x80);
                    P0 = 0xFE;
                    P2 &= 0x1f;
                    uart_sendstring("1");
                }
                break;
                case '2':
                {
                    P2 = ((P2 & 0x1f) | 0x80);
                    P0 = 0xFD;
                    P2 &= 0x1f;
                    uart_sendstring("2");
                }
                break;
                case '3':
                {
                    P2 = ((P2 & 0x1f) | 0x80);
                    P0 = 0xFB;
                    P2 &= 0x1f;
                    uart_sendstring("3");
                }
                break;
                case '4':
                {
                    P2 = ((P2 & 0x1f) | 0x80);
                    P0 = 0xF7;
                    P2 &= 0x1f;
                    uart_sendstring("4");
                }
                break;
                case '5':
                {
                    P2 = ((P2 & 0x1f) | 0x80);
                    P0 = 0xEF;
                    P2 &= 0x1f;
                    uart_sendstring("5");
                }
                break;
                case '6':
                {
                    P2 = ((P2 & 0x1f) | 0x80);
                    P0 = 0xDF;
                    P2 &= 0x1f;
                    uart_sendstring("6");
                }
                break;
                case '7':
                {
                    P2 = ((P2 & 0x1f) | 0x80);
                    P0 = 0xBF;
                    P2 &= 0x1f;
                    uart_sendstring("7");
                }
                break;
                case '8':
                {
                    P2 = ((P2 & 0x1f) | 0x80);
                    P0 = 0x7F;
                    P2 &= 0x1f;
                    uart_sendstring("8");
                }
                break;
                default:
                    uart_sendstring("error\r\n");	//输入其他数据返回error
                    break;
            }
            ES = 1;
        }
    }
}

void isr_uart(void) interrupt 4         //UART1中断的中断号为4
{
     /*
        发送数据之前,并未发送数据,
        恰恰说明单片机已经接收到了数据,
        硬件会将RI置1,
        此时SBUF中接收到的数据为空。
    
    */
    if(RI)                              //RI接收中断请求标志位,接受到8位数据后由硬件置1
    {
        RI = 0;                         //清除接受标志位
        Rx_data = SBUF;
        ES = 0;                         //串口中断允许标志位,置0,禁止中断
        Rx_flag = 1;
        
    }
}

void uart_sendstring(unsigned char *str)
{
    unsigned char *p;
    p = str;
    while(*p != '\0')
    {
        SBUF = *p;
        while(TI == 0);                 //串口1发送中断标志,方式0中,发送完8位数据后,由硬件置1
        /*
            此处等待中断标志位由硬件置1
        */
        TI = 0;
        p++;
    }
}

PC向MCU发送1~8任意一个数字,8个LED按从右向左递减的位置显示接收到的数字对应的位置,同时MCU将接收到的数据再发送给PC

3.内容要点

SCON = 0X50;            //串行控制寄存器,8位UART,波特率可变

AUXR = 0X40;            //辅助寄存器,定时器1时钟1T模式

 

将T1x12置1,设置定时器为1T模式,不分频。将S1ST2置0 ,选择定时器1作为串口1的波特率发生器。

波特率发生器在串行通信中用于确保数据能够以正确的速率被发送或接收。当使用定时器作为波特率发生器时,每次中断的工作流程主要用于控制比特的发送或接收时间。以下是一个简化的过程描述,解释了每次中断是如何工作的,特别是在发送数据的情况下:

### 中断工作原理

1. **初始化阶段**:
   - 配置定时器:根据所需的波特率和系统时钟频率,设置定时器的预分频系数和比较值(或者溢出值),使得定时器每隔一个比特周期触发一次中断。例如,在9600波特率下,每个比特时间为104微秒。
   - 准备数据帧:组织好要发送的数据帧,通常包括起始位、数据位(通常是8位)、奇偶校验位(可选)和停止位。

2. **开始发送数据**:
   - 启动定时器并发送起始位:通过设置UART TX引脚为低电平来表示起始位,并启动定时器。
   
3. **中断服务程序(ISR)执行**:
   - **每次中断触发**:当定时器计数到预设值时,会产生一个中断请求,CPU暂停当前任务跳转至中断服务程序(ISR)。
   - 在ISR中:
     - **切换TX引脚状态**:根据当前需要发送的比特位置更新TX引脚的状态(高电平或低电平)。首先发送最低有效位(LSB),然后依次发送直至最高有效位(MSB)。
     - **管理比特计数器**:维护一个内部计数器来跟踪已经发送了多少个比特。每发送完一位,该计数器递增。
     - **检查是否完成数据帧发送**:如果所有比特(包括起始位、数据位、奇偶校验位(如果有)、停止位)都已发送完毕,则可以在ISR中关闭定时器,或者标记发送完成标志以便主程序处理下一个待发送的数据字节。

在定时器中断服务程序(ISR)中执行的操作主要是为了确保数据能够按照设定的波特率准确地发送或接收。每次中断发生时,意味着一个比特周期已经过去,这时需要处理当前比特的数据并为下一个比特做准备。以下是在中断服务程序中可能执行的主要步骤:

### 发送数据时的中断处理

1. **更新计数器**:
   - 每次进入中断服务程序时,首先增加比特计数器,用于跟踪当前正在发送或接收的是哪一个比特。

2. **发送起始位**:
   - 如果这是发送过程中的第一个中断(即比特计数器为0),则设置UART TX引脚为低电平以发送起始位。

3. **发送数据位**:
   - 根据比特计数器的值,从最低有效位(LSB)到最高有效位(MSB)依次发送数据位。这通常涉及到将待发送字节与一个掩码进行操作来提取当前应发送的比特值,并相应地设置TX引脚的状态。
   
4. **处理奇偶校验位(如果使用的话)**:
   - 在所有数据位发送完毕之后,根据所选择的奇偶校验方式计算并发送奇偶校验位。

5. **发送停止位**:
   - 最后,在所有数据位和奇偶校验位(如果有)发送完毕后,设置TX引脚为高电平来发送停止位。

6. **检查是否完成**:
   - 判断是否所有的比特(包括起始位、数据位、奇偶校验位和停止位)都已发送完毕。如果是,则可以关闭定时器或者重置状态机以便开始下一次传输。

7. **清除中断标志**:
   - 最后不要忘记清除定时器的中断标志,允许下一次中断的发生。

TMOD &= 0x00;               //定时器/计时器工作模式寄存器,将定时器1设置为16位自动重载定时器

    TL1 = (65536 - (SYSclk / 4 / BAUD));
    TH1 = (65536 - (SYSclk / 4 / BAUD)) >> 8;

 

TR1 = 1;                //定时器1控制允许位

ES = 1;                 //串口1中断允许位
EA = 1;                 //总中断允许位

void isr_uart(void) interrupt 4         //UART1中断的中断号为4
{
     /*
        发送数据之前,并未发送数据,
        恰恰说明单片机已经接收到了数据,
        硬件会将RI置1,
        此时SBUF中接收到的数据为空。
    
    */
    if(RI)                              //RI接收中断请求标志位,接受到8位数据后由硬件置1
    {
        RI = 0;                         //清除接受标志位
        Rx_data = SBUF;
        ES = 0;                         //串口中断允许标志位,置0,禁止中断
        Rx_flag = 1;
        
    }
}

 

 

void uart_sendstring(unsigned char *str)
{
    unsigned char *p;
    p = str;
    while(*p != '\0')
    {
        SBUF = *p;
        while(TI == 0);                 //串口1发送中断标志,方式0中,发送完8位数据后,由硬件置1
        /*
            此处等待中断标志位由硬件置1
        */
        TI = 0;
        p++;
    }
}

4.实验结果

        实验1

        实验2

<think>好的,用户想了解蓝桥杯比赛中单片机串口通信的示例代码和调试技巧。首先,我需要确定他们使用的单片机型号,蓝桥杯通常使用STC15系列,比如STC15F2K60S2。所以示例代码应该基于这个型号。 接下来,串口通信的基本配置包括波特率设置、定时器初始化、中断配置等。需要确认常用的波特率,比如9600,并确保定时器1工作在模式2,自动重装载。同时,记得设置ES和EA开启中断。 然后,示例代码的结构要清晰,包括主函数初始化、中断服务函数处理发送和接收。发送部分可能使用查询方式,接收部分使用中断。注意TI和RI标志位的处理,避免数据覆盖。 调试技巧方面,硬件检查很重要,比如线缆连接和电压。使用示波器或逻辑分析仪查看波形是否正确。软件上,可以发送测试字符验证通信,检查波特率计算是否正确。常见问题比如数据乱码可能是波特率不匹配,数据丢失可能是缓冲区溢出,需要提醒用户注意。 还需要生成相关问题,覆盖初始化步骤、提高可靠性的方法、多机通信等。确保问题有针对性,帮助用户深入理解。 最后,检查LaTeX格式是否正确,比如波特率计算公式用$$...$$,变量用$...$。引用部分要自然,比如提到数据手册时添加引用标识。确保回答结构清晰,分点明确,代码格式正确,符合用户的要求。</think># 蓝桥杯单片机串口通信实现指南 ## 一、硬件配置基础 STC15系列单片机内置增强型UART模块,支持模式1(8位UART)工作方式[^1]。典型接线方式: - TXD(P3.1)连接PC端RXD - RXD(P3.0)连接PC端TXD - 共地连接 $$ 波特率 = \frac{2^{SMOD}}{32} \times \frac{f_{osc}}{12 \times (256 - TH1)} $$ ## 二、示例代码(STC15F2K60S2) ```c #include <STC15.H> #define BRT (65536 - FOSC / 115200 / 4) // 11.0592MHz晶振 unsigned char UART_BUF[64]; unsigned char cnt = 0; void UART_Init() { SCON = 0x50; // 模式1,允许接收 AUXR |= 0x04; // 定时器1时钟为Fosc/4 TMOD &= 0x0F; // 清除定时器1模式位 TL1 = BRT; // 初始化定时值 TH1 = BRT >> 8; TR1 = 1; // 启动定时器1 ES = 1; // 使能串口中断 EA = 1; } void UART_SendByte(unsigned char dat) { SBUF = dat; while(!TI); TI = 0; } void UART_SendStr(unsigned char *s) { while(*s) { UART_SendByte(*s++); } } void UART_ISR() interrupt 4 { if(RI) { RI = 0; UART_BUF[cnt++] = SBUF; if(cnt >= 64) cnt = 0; } } void main() { UART_Init(); while(1) { if(cnt > 0) { UART_SendStr(UART_BUF); cnt = 0; } } } ``` ## 三、调试技巧 1. **硬件检查** - 确认USB转TTL模块的驱动安装 - 测量TXD/RXD引脚电压(正常约3.3V) - 使用万用表检测线路通断 2. **软件调试** - 先发送固定字符测试(如0x55) - 用示波器测量波特率误差(应小于2%) - 使用串口助手十六进制显示模式 3. **常见问题处理** - 数据乱码:检查晶振频率设置,确认$SMOD$位配置 - 接收不完整:增加接收缓冲区,添加帧头帧尾校验 - 数据丢失:降低波特率或优化中断响应时间 ## 四、性能优化建议 1. 使用双缓冲机制提升吞吐量 2. 添加奇偶校验位提高可靠性 3. 采用MODBUS协议格式实现标准通信[^2] 4. 使用$DMA$传输(需芯片支持) [^1]: STC15系列数据手册UART章节 [^2]: MODBUS协议规范文档
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值