串口通信

串口是指外设和处理器之间通过数据信号线、地线和控制线等,按位进行传输数据的一种通讯方式。尽管传输速度比并行传输低。但串口可以在使用一根线发送数据的同时用另一根线接收数据。 这种通信方式使用的数据线少,在远距离通信中可以节约通信成本。串口通信最重要的参数是波特率、数据位、停止位和奇偶校验位,这些参数在两个通信端口之间必须一致。

串口工作模式分为三种:单工、全双工模式和半双工模式。

  • 单工:在通信的任意时刻,信息只能由 A 传到 B,或 B 传到 A;
  • 半双工:在通信的任意时刻,信息即可由 A 传到 B,又能由 B 传到 A,但同时只能有一个方向上的传输存在;
  • 全双工:在通信的任意时刻,通信线路上存在 A 到 B 和 B 到 A 的双向信号传输;

串口通信协议

串口通信协议定义了在串口上进行数据交换的规则和格式。常见的串口通信协议包括 ASCII 协议、Modbus 协议、RS-232 协议等。协议规定了数据的帧结构、数据格式、校验方式等,确保发送和接收双方按照相同的规则进行数据交换,从而实现数据的正确传输和解析。

串口通信是一位一位地传输,每传输一个字符总是以起始位开始,以停止位结束,字符之间没有固定的时间间隔要求。每一个字符的前面都有一位起始位(低电平),后面由 7 位数据位组成,接着是一位校验位,最后是停止位。停止位后面是不定长的空闲位,停止位和空闲位都规定为高电平。

uart.png

单片机端设置

注意:在使用外部设备与串口通信时,要将Launchpad 的J21 J22跳线帽接到下方

对于串口通信来说,发挥主要作用的便是串口中断函数,在接收中断中,在接收到数据后,系统便会自动执行串口中断函数中的内容,下面是一个简单实现接收数据的串口中断程序

void UART_0_INST_IRQHandler(void)
{
	// 如果产生了串口中断
	switch (DL_UART_Main_getPendingInterrupt(UART_0_INST))
	{
	case DL_UART_MAIN_IIDX_RX: // 如果是接收中断
		// 接发送过来的数据保存在变量中
		uart_data = DL_UART_Main_receiveData(UART_0_INST);
		writeRingBuff(uart_data);
		break;

	default: // 其他的串口中断
		break;
	}
}

储存串口传输的数据的变量定义在代码前端

volatile uint8_t uart_data = 0;

这样,通过在main函数中启用中断,便可以实现最简单的串口中断调用

// 清除串口中断标志
NVIC_ClearPendingIRQ(UART_0_INST_INT_IRQN);
// 使能串口中断
NVIC_EnableIRQ(UART_0_INST_INT_IRQN);

Printf的重定向

若要使用printf函数,需要在main文件里对其进行重定向,并在头文件中加上

#include "stdio.h"

#if !defined(__MICROLIB)
//不使用微库的话就需要添加下面的函数
#if (__ARMCLIB_VERSION <= 6000000)
//如果编译器是AC5  就定义下面这个结构体
struct __FILE
{
        int handle;
};
#endif

FILE __stdout;

//定义_sys_exit()以避免使用半主机模式
void _sys_exit(int x)
{
        x = x;
}
#endif
//printf函数重定义
int fputc(int ch, FILE *stream)
{
        //当串口0忙的时候等待,不忙的时候再发送传进来的字符
        while( DL_UART_isBusy(UART_0_INST) == true );

        DL_UART_Main_transmitData(UART_0_INST, ch);

        return ch;
}

因为 printf 中使用到了 %f 格式输出,需要开启 micro LIB,并配置堆栈大小

i2c_20241012_152630.png

串口屏端

方法一 使用TJC提供的头文件进行编写

淘晶驰串口屏的配置可以通过引入tjc_usart_hmi.c文件大幅简化开发流程,该官方提供的头文件中包含了基本的字符、字符串、以及环形缓冲区的设定

单片机通过串口发送指定字符串实现对串口屏端的控制

实现思路大致为先将控制指令赋值为一个string类型变量,再通过串口发送出去,串口屏端接收到字符串后会将其解析为命令

注意:通信协议中要求在包尾加上/xff/xff/xff即三个十六进制的FF

string str[100];
sprintf(str,"指令内容");
tjc_send_string(str);

tjc_send_string函数中包含了串口通信的包头包尾协议,无需再添加

串口屏端指令参考指令集 — 淘晶驰串口屏资料中心 1.1.0-2025-07-24 10:19:55 文档

方法二 使用printf函数进行编写

如果想自行编写串口的函数,我推荐将tjc_usart_hmi.c中关于环形缓存区的函数与宏定义搬运过来,再通过printf重定向,这样可以精简代码,不过要注意手动加上通信协议的包尾/xff/xff/xff

比如,对串口屏上的指定界面的文本控件显示文本,对page0页面的s0控件的txt属性进行更改

printf("page0.s0.txt=/"This is a test/"/xff/xff/xff");

或者将程序中的变量值传递过去,将代码中属性为int的variable的值显示在page0页面的s0控件上

printf("page0.s0.txt=/&d/xff/xff/xff",variale);