人生的第一次串口打印

本文介绍了如何在单片机上实现串口通讯,包括配置串口、发送和接收数据,以及使用printf通过串口打印。通过设置波特率和数据帧格式,发送hello.word!作为测试。文章还涉及了中断服务函数,用于处理RI和TI标志,以及数据接收的校验和处理。最后,提到了如何通过结构体存储接收到的数据并进行检查。

人生的第一次串口打印

双机通讯是不是很神奇,特别是自己实现的,今天就实现一个最经典的“hello.word!”的打印
在上一篇文章中,学会了串口的配置,如果还有不懂得,可以去看看

第一步,串口是如何工作的

还是以8位UART格式为例,一帧信息是10位,也就是10bit:一个起始位,八个数据位(低位在先),一个停止位。所以串口每执行一次写或者读SUBF时,都是传输一帧10位数据,波特率的意思就是一秒钟可以发送多少帧数据,比如9600bsp,就是1秒钟可以接受9600/10=960帧的数据。

执行过程

以模式一8位UART为例,串口发送数据时,数据由串行发送端TXD输出,当主机执行一条写SBUF指令,就启动串行通信发送,当数据全部通过移位寄存器,打开控制器开关TI = 1,将数据发送出去,一般这样简单理解就可以,没必要深究。
所以第一步就是配置串口,上一篇文章已经配置好了

void Uart1_Init(void) // 9600bps@22.1184MHz
{
    SCON = 0x50;  // 8位数据,可变波特率
    AUXR |= 0x40; // 定时器时钟1T模式
    AUXR &= 0xFE; // 串口1选择定时器1为波特率发生器
    TMOD &= 0x0F; // 设置定时器模式
    TL1 = 0xC0;   // 设置定时初始值
    TH1 = 0xFD;   // 设置定时初始值
    ET1 = 0;      // 禁止定时器中断
    TR1 = 1;      // 定时器1开始计时
    ES  = 1;	  //串口中断打开
    EA  = 1;	  //总中断打开
}

然后就是发送一个字节

void Uart1_SendByte(uint8_t b)
{
    // Uart1.tx_flag = 0;
    SBUF = b; // 发送一个字节,将其值赋给SBUF
    // while(!Uart1.tx_flag);
    while (TI == 0);
    TI = 0; // 数据发送完后TI自动置一,需要软件置零
}

一共两种方式,都可以,任选一种,不过更建议采用有标志位的,可以做一些判断操作。比如

if(Uart1_tx_flag == 1)
{
/******写自己要做的操作****/
}

有时候不仅仅发送一个字节,可能会是一个字符串,就需要重复写一个字节的过程

void Uart1_SendStr(uint8_t *str)
{
    while (*str) {
        Uart1_SendByte(*str++); // 将串口传进来的值取地址,并且将地址上的值依次送给SBUF
    }
}

我们一直说想通过printf打印一些关键节点,这就需要进行串口重定向

什么意思呢,就是51单片机没办法直接将printf的值通过打印出来,需要借助putchar()来实现,相当于是printf和单片机串口之间的翻译或者说桥梁

char putchar(char c)
{
    Uart1_SendByte(c);
    return c;
}

有时候我们会对传回来的值进行校验,判断是否是我们想要的,有时候会对传输值进行判断。比如起始值,控制位。校验码,结束符等等关键字符,这个怎么做呢,我的思路比较简单,就是将传回来的值,放到一个数组里面,然后通过提取数组中的值进行判断,符合要求的,输出数据段,不符合要求的,就舍弃这段数据,通过printf可以判断哪一步产生了哪些值。
言过正传,先写串口的打印字符串,
前面的写了这么多,会有人问,那RI怎么处理
接下来就是RI的判断处理了,一般是在中断函数中进行的

void Uart1_Isr(void) interrupt 4
{
    if (TI == 1) {
        TI = 0;
        Uart1.tx_flag = 1;
    }
    if (RI == 1) // 数据接收完成后自动置一
    {
     	Uart1.tx_flag = 1;
        RI = 0; // 数据接收完成后由软件自动清零
    }
}

写完串口函数,接下来就是主函数的打印,首先我们测试打印一个字符串


void main(void)
{
	Uart1_SendStr("Hello,word!");
	while(1)
	{
	///
	}
} 

在这里插入图片描述
打开串口助手,然后按复位键,就显示了hello,word!
,这种是最简单的,是写在程序里面的,我们要通过串口给他写值,让他打印该怎么做呢,继续往下看:
我们可以在终端中做一些处理
首先,我们先定义一个结构体,用来存放这些接收的数据值

#define RX_MAX  (64U)
typedef struct 
{
    uint8_t tx_flag;
    
    uint8_t rx_flag;
    uint8_t rx_len;
    uint8_t rx_buffer[RX_MAX];
}TsUart;

然后在中断函数中,做一些处理,当传回来的值大于6,小于64的时候,我们认为其有效,将这部分值提取出来,放到我们的结构体数组中,进行处理

void Uart1_Isr(void) interrupt 4
{
    uint8_t temp;
    if (TI == 1) {
        TI = 0;
        Uart1.tx_flag = 1;
    }

    if (RI == 1) // 数据接收完成后自动置一
    {
        if (Uart1.rx_len < RX_MAX) 
        {
            Uart1.rx_buffer[Uart1.rx_len++] = SBUF; // 将值放在Uart1.rx_buffer[]中
        }
        if (Uart1.rx_len >= 6)
        {
            Uart1.rx_flag = 1;
        }
        
        if (Uart1.rx_len >= RX_MAX) {
            temp          = SBUF;
            Uart1.rx_len  = RX_MAX;
            Uart1.rx_flag = 1;
        }
        RI = 0; // 数据接收完成后由软件自动清零
    }
}

然后我们可以声明一个检查函数,用来查看和检验,比如我们要看传回来几位数,里面的内容是什么

void Uart1_ReceiveCheck(unsigned char d)
{
    uint8_t i;
    printf("value: ");

    for (i = 0; i < d; i++) 
    {
        // printf("0x%02bX ", Uart1.rx_buffer[i]);
           Uart1_SendByte(Uart1.rx_buffer[i]); 
        // printf("%c ", Uart1.rx_buffer[i]);
    }
    printf("\r\n");
}

一共举了三个例子,第一个是以16进制查看接受的值,第二个就是直接将接收的值打印出来,第三个是以字符方式打印出来
具体什么格式输出可以参考这篇link

在这里插入图片描述
主函数中的while用作处理就行

    while (1)
    {
        if (Uart1.rx_flag == 1)
        {
            Uart1.rx_flag = 0;

            printf("Uart1.rx_len = %02bd\r\n", Uart1.rx_len);
            Uart1_ReceiveCheck(Uart1.rx_len);
            
            memset(Uart1.rx_buffer, 0, Uart1.rx_len); // 清除緩存值
            Uart1.rx_flag = 0;
            Uart1.rx_len = 0;
        }
    }

这篇有点长了,那天有时间,将前面说的校验值,控制位讲一下,因为有的需要这种判断
例如在这里插入图片描述
写这个纯脆为了自学巩固,哪里错里很正常,欢迎大佬指正!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值