本帖最后由 袁胜富 于 2023-1-3 01:13 编辑
#申请原创# #技术资源# 一、前言
首先非常感谢雅特力提供的开发板,基于此我本人发表此篇文章。
二、项目介绍
AT32F437主频高达288MHZ和大容量的Flash和SRAM,非常适合跑操作系统,在操作系统上我们可以做很多复杂的应用逻辑,其优势远远超过了裸机的轮询方法。因此我特别在AT32F437上跑TencentOS-tiny这个开源操作系统。在此篇文章中我只在系统上跑一个淘晶驰串口屏任务,让串口屏显示ATF437发送的数据,以及串口屏发送数据给AT32F437处理,然后通过USART1打印出来。
三、准备工作
1.淘晶驰串口屏开发上位机安装,首先到淘晶驰官网安装最新的上位机,【USART HMI】软件最新版本Ver1.64.,网址:上位软件下载:1.最新版本下载 [USART HMI 资料中心] (tjc1688.com),进入网址选择方式如下图所示
软件下载后,将压缩包解压,软件安装NEXT就行。。。。。,
软件安装好后,打开上位机,新建工程
设备型号选择
显示方向及字符编码选择
字库制作,不制作字库无法有效显示文字
字库参数设置及命名
界面编辑,在界面上放置两个文本框作为标签,放置两个文本框用来接收显示数据和改变文本框背景色和放置三个状态开关。如下图所示
新建变量UART_String,最大长度30,用做串口数据发送变量字符串,通过改变状态开关,发送不同的字符命令到AT32F437控制3颗LED的状态
UART_String.txt=""
if(LED1.val==0)
{
UART_String.txt="!LEDx_OFF#"//--------其中可以是1,2,3
prints UART_String.txt,0
}
假如状态开关LED1状态值为1就发送!LED1_ON#,假如状态开关LED1状态值为0就发送!LED1_OFF#,其他状态按钮以此类推。
此外,还需要在界面初始化加入如下代码,bauds=115200代表单片机和串口屏的波特率为115200,dims=100代码屏幕背光亮度最亮
//以下代码只在上电时运行一次,一般用于全局变量定义和上电初始化数据
int sys0=0,sys1=0,sys2=0 //全局变量定义目前仅支持4字节有符号整形(int),不支持其他类型的全局变量声明,如需使用字符串类型可以在页面中使用变量控件来实现
bauds=115200
dims=100
code_c
page 0 //上电刷新第0页
编写好串口屏代码后,需要将 编译好的代码烧写进串口屏,我们利用板载的ATLink的串口来烧录吧,接线方式如下图所示
连接好线后,开始下载,步骤如下图所示
注:
1.设备接收指令结束符为”0XFF 0XFF 0XFF”三个字节(HEX数据,不是字符串数据)。 2.所有指令名以及参数全部使用ASCII字符串数据,非HEX数据,便于阅读和调试。 3. 所有指令名使用小写字母(此处仅仅指的是指令名称为小写,参数该大写的时候还是要大写)。 通过学习,我们知道要想与串口的控件进行数据的交互,那么必须要有下位机(单片机)与串口屏的通信协议,
一、串口数据解析模式之被动解析模式 在默认情况下屏接收设备发送数据完整格式为字符串指令加上3个16进制ff,如果屏接收到不完整或者错误指令将会返回数据。例如①1a ff ff ff ②1c ff ff ff等;可通过bkcmd指令进行开启关闭返回数据。(在正常情况下建议先将屏幕报错原因找到解决了,再指令关闭返回数据) 1.1 以文本控件显示为例 单片机如何控制屏幕(文本控件) 1、在上位机工程新建一个文本控件,假设为t0,将程序下载到串口屏上,
2、串口屏串口与单片机串口连接,两者波特率应一致,单片机RX接串口屏TX,单片机TX接串口屏RX。
3、发送指令:单片机串口通过字符串模式发送t0.txt="六六六"
4、发送结束符:单片机通过HEX模式发送0xff 0xff 0xff
5、此时屏幕上的t0控件内的文字变为“六六六”
1.2 以数字控件显示为例 单片机如何控制屏幕(数字控件) 1、在上位机工程新建一个数字控件,假设为n0,将程序下载到串口屏上,
2、串口屏串口与单片机串口连接,两者波特率应一致,单片机RX接串口屏TX,单片机TX接串口屏RX。
3、发送指令:单片机串口通过字符串模式发送n0.val=666
4、发送结束符:单片机通过HEX模式发送0xff 0xff 0xff 5、此时屏幕上的n0控件内的文字变为“666”
1.3 单片机发送变量到屏幕 1.3.1 C语言为例 在通常情况下单片机是很少发送一个常量给屏赋值的,大多数情况都是单片机赋值一个变量到屏幕上的。下面代码以C语言为例
printf("n0.val=666"); 发送命令
printf("\xff\xff\xff"); 发送结束符
printf("n0.val=666\xff\xff\xff");
printf("n0.val=%d\xff\xff\xff",MyData); 一次性发完命令和结束符
printf("t0.txt=\"%d\"\xff\xff\xff",MyTxt); 一次性发完命令和结束符 注:这里发送16进制是用\xff,若不明白"\"使用法,自行百度"c语言转义字符"。
1.3.2 anduino单片机为例 Serial.print("t0.txt=\"你好\""); 发送字符串命令 Serial.write(hexEND,3); 发送3个16进制ff结束符 此时屏幕t0文本控件会显示"你好"。 Serial.print("n0.val=666"); 发送字符串命令 Serial.write(hexEND,3); 发送3个16进制ff结束符 此时屏幕n0数字控件会显示"666"。
Serial.print("n0.val=”+part); 发送字符串命令 Serial.write(hexEND,3); 发送3个16进制ff结束符 以上资料来自淘晶驰资料。通过以上学习基本就知道怎么使用串口屏幕啦。 四、C语言代码编写 1.HMI.h头文件编写 #ifndef __HMI_H #define __HMI_H
#include "at32f435_437_board.h" #define UART_BufferSize 255
typedef struct { uint8_t RxBuffer[UART_BufferSize]; //数据接收缓冲区 uint8_t CommandBuffer[UART_BufferSize]; //命令数据接收缓冲区 uint16_t RxCnt;//数据接收长度 uint8_t Rxfinish;//接收完成标志 }UART_DataType;
extern UART_DataType uartData[1];
void HMI_UART2_Init(uint32_t baudRate); void HMI_UART2_Printf(char *fmt,...); void HMI_UART2_SendChar(uint8_t Char); void HMIUART_Screen_Object_SendData(char Obiect[],char Object_Attribute[],char *Object_Value,...);
#endif 2.HMI.c源文件文件编写
#include "HMI.h" #include "tos_k.h" #include "stdio.h" #include "stdarg.h" #include "string.h" #include "stdlib.h"
UART_DataType uartData[1] = {0};//数据接收结构
void HMI_UART2_Init(uint32_t baudRate) { gpio_init_type gpio_init_struct; /* enable the uart and gpio clock */ crm_periph_clock_enable(CRM_USART2_PERIPH_CLOCK, TRUE); crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);
gpio_default_para_init(&gpio_init_struct); /* configure the uart tx pin */ /* configure the usart2 tx, rx pin */ gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER; gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL; gpio_init_struct.gpio_mode = GPIO_MODE_MUX; gpio_init_struct.gpio_pins = GPIO_PINS_2 | GPIO_PINS_3; gpio_init_struct.gpio_pull = GPIO_PULL_NONE; gpio_init(GPIOA, &gpio_init_struct); gpio_pin_mux_config(GPIOA, GPIO_PINS_SOURCE2, GPIO_MUX_7); gpio_pin_mux_config(GPIOA, GPIO_PINS_SOURCE3, GPIO_MUX_7); /* configure usart2 param */ usart_init(USART2, 115200, USART_DATA_8BITS, USART_STOP_1_BIT); usart_transmitter_enable(USART2, TRUE); usart_receiver_enable(USART2, TRUE); nvic_irq_enable(USART2_IRQn, 0, 0); /* enable usart2 and usart3 interrupt */ usart_interrupt_enable(USART2, USART_RDBF_INT, TRUE); usart_enable(USART2, TRUE); } void HMI_UART2_Printf(char *fmt,...) { uint8_t T1_Bufferr[255]; uint16_t i,j; va_list ap; va_start(ap,fmt); vsprintf((char*)T1_Bufferr,fmt,ap); va_end(ap); i=strlen((char*)T1_Bufferr); for(j=0;j<i;j++) { HMI_UART2_SendChar(T1_Bufferr[j]); } }
void HMI_UART2_SendChar(uint8_t Char) { while(usart_flag_get(USART2, USART_TDBE_FLAG) == RESET); usart_data_transmit(USART2, Char); } void HMIUART_Screen_Object_SendData(char Obiect[],char Object_Attribute[],char *Object_Value,...) { uint8_t T1_Bufferr[255]; va_list ap; va_start(ap,Object_Value); vsprintf((char*)T1_Bufferr,Object_Value,ap); va_end(ap); if((strstr(Object_Attribute,"txt") !=0) )//对象控件的属性位文本类型 { HMI_UART2_Printf("%s.%s=\"%s\"",Obiect,Object_Attribute,T1_Bufferr); } else if((strstr(Object_Attribute,"bco") !=0) || (strstr(Object_Attribute,"pco") !=0) || (strstr(Object_Attribute,"pw") != 0))//对象控件的属性位数值类型 { HMI_UART2_Printf("%s.%s=%s",Obiect,Object_Attribute,T1_Bufferr); } HMI_UART2_SendChar(0xFF); HMI_UART2_SendChar(0xFF); HMI_UART2_SendChar(0xFF); }
/** * @brief this function handles usart2 handler. * @param none * @retval none */ void USART2_IRQHandler(void) { uint8_t CH; if(tos_knl_is_running()) { tos_knl_irq_enter(); if(USART2->ctrl1_bit.rdbfien != RESET) { if(usart_flag_get(USART2, USART_RDBF_FLAG) != RESET) { CH = usart_data_receive(USART2); if(UART_BufferSize >= uartData[0].RxCnt) { if(((CH == '!') || (uartData[0].RxBuffer[0] == '!')) && (uartData[0].Rxfinish == 0)) { uartData[0].RxBuffer[uartData[0].RxCnt++] = CH; if((uartData[0].RxBuffer[0] == '!') && (CH == '#')) { strncpy((char*)uartData[0].CommandBuffer,(char*)uartData[0].RxBuffer+1,strlen((char*)uartData[0].RxBuffer)-2); uartData[0].Rxfinish = 1; } } } else { uartData[0].RxCnt = 0; uartData[0].Rxfinish = 0; memset(uartData[0].RxBuffer,0,UART_BufferSize); } } } tos_knl_irq_leave(); } }
3.main.c源文件文件编写 #include "at32f435_437_board.h" #include "at32f435_437_clock.h" #include "HMI.h" #include "tos_k.h"
#define APPLICATION_TASK_STK_SIZE 1024 k_task_t application_task; uint8_t application_task_stk[APPLICATION_TASK_STK_SIZE]; #define hmi_uart_TASK_STK_SIZE 1024 k_task_t hmi_uart_task; uint8_t hmi_uart_task_stk[hmi_uart_TASK_STK_SIZE]; #define hmi_uartReceive_TASK_STK_SIZE 1024 k_task_t hmi_uartReceive_task; uint8_t hmi_uartReceive_task_stk[hmi_uartReceive_TASK_STK_SIZE]; extern void application_entry(void *arg);
__weak void application_entry(void *arg) { int i= 0; while (1) { for(i=0;i<65535;i++) { HMIUART_Screen_Object_SendData("TEXT1","txt","%d",i); tos_task_delay(1000); } } }
__weak void hmi_uart_entry(void *arg) { while (1) { HMIUART_Screen_Object_SendData("TEXT2","bco","%d",63488);//串口屏文本框显示红色 tos_task_delay(500); HMIUART_Screen_Object_SendData("TEXT2","bco","%d",2016);//串口屏文本框显示绿色 tos_task_delay(500); HMIUART_Screen_Object_SendData("TEXT2","bco","%d",31);//串口屏文本框显示蓝色 tos_task_delay(500); } }
__weak void hmi_uartReceive_entry(void *arg) { while (1) { tos_task_delay(1); if(uartData[0].Rxfinish == 1) { printf("%s\r\n",uartData[0].CommandBuffer); if(strstr((char*)uartData[0].CommandBuffer,"LED1_ON") != NULL) { at32_led_on(LED2); } if(strstr((char*)uartData[0].CommandBuffer,"LED1_OFF") != NULL) { at32_led_off(LED2); } if(strstr((char*)uartData[0].CommandBuffer,"LED2_ON") != NULL) { at32_led_on(LED3); } if(strstr((char*)uartData[0].CommandBuffer,"LED2_OFF") != NULL) { at32_led_off(LED3); } if(strstr((char*)uartData[0].CommandBuffer,"LED3_ON") != NULL) { at32_led_on(LED4); } if(strstr((char*)uartData[0].CommandBuffer,"LED3_OFF") != NULL) { at32_led_off(LED4); } uartData[0].RxCnt = 0; uartData[0].Rxfinish = 0; memset(uartData[0].CommandBuffer,0,UART_BufferSize); memset(uartData[0].RxBuffer,0,UART_BufferSize); } } } /** * @brief main function. * @param none * @retval none */ int main(void) { system_clock_config(); at32_board_init(); HMI_UART2_Init(115200); printf("Welcome to TencentOS tiny(%s)\r\n", TOS_VERSION); tos_knl_init(); // TencentOS Tiny kernel initialize tos_task_create(&application_task, "application_task", application_entry, NULL, 0, application_task_stk, APPLICATION_TASK_STK_SIZE, 0); tos_task_create(&hmi_uart_task, "hmi_uart_task", hmi_uart_entry, NULL, 0, hmi_uart_task_stk, hmi_uart_TASK_STK_SIZE, 0); tos_task_create(&hmi_uartReceive_task, "hmi_uartReceive_task", hmi_uartReceive_entry, NULL, 0, hmi_uartReceive_task_stk, hmi_uartReceive_TASK_STK_SIZE, 0); tos_knl_start(); while(1) { __NOP(); } }
五、效果展示 编写完代码,就该欣赏运行效果了,展示如下图,关于视频请移步Bilibili,链接:【AT32F437与淘晶驰串口屏进行数据通信交互。-哔哩哔哩】 https://b23.tv/UWd2n1t,工程源码已经放置在附件,感兴趣的朋友可以玩玩。
|