Description
STM32F103和“乐升”串口屏的串口指令交互(初级)
栏目:公司新闻 发布时间:2024-07-16
 1. 电脑串口调试乐升串口屏  2. STM32程序配置  2.1. CRC计算处理  2.2. UART串口配置  2.3. 主函数编写进行指令传输  2.4. 串口通讯连接  3. 串口调试工具(UI_Debugger-II)使用说明  3.1. 软件主界面  3.1.1. 指令编辑区  3.1.2. 信息区  3.1.3. 功能区  3.1.4. 配置信息区  3.1.5. 循环配置区

  1. 电脑串口调试乐升串口屏

  2. STM32程序配置

  2.1. CRC计算处理

  2.2. UART串口配置

  2.3. 主函数编写进行指令传输

  2.4. 串口通讯连接

  3. 串口调试工具(UI_Debugger-II)使用说明

  3.1. 软件主界面

  3.1.1. 指令编辑区

  3.1.2. 信息区

  3.1.3. 功能区

  3.1.4. 配置信息区

  3.1.5. 循环配置区

  3.1.6. 信息操作区

  3.1.7. 指令行处右键呼出菜单项

  3.1.8. 在 Select 列右键点击可以全选或全不选指令,如下图

  3.2. 指令发送使用教程

  3.2.1. 发送单条指令

  3.2.2. 一次发送多条指令与循环发送指令

  3.3. 指令文档说明

  3.4. 指令信息文档说明

  通过串口助手和串口转USB模块可以实现电脑对乐升串口屏的串口调试。首先需要将串口转USB模块的RXD和TXD引脚同串口屏的RXD和TXD引脚交叉相连,GND与GND连接形成共地。将串口转USB模块插入电脑USB口(需要提前安装串口转USB模块的相应驱动,具体请自行咨询购买商家或厂家)。打开串口调试助手,识别到串口接入的COM口后选择对应COM口,波特率改为115200,打开串口,选择16进制显示和16进制发送。在下方窗口输入串口指令即可对串口屏进行调试,上方大窗口为串口屏反馈内容。

  具体设置如图所示:

  接下来演示通过串口调试助手进行串口屏切页操作,选择切页到第2页,串口指令为5a a5 07 10 70 00 00 02 7e c2,输入指令框后点击右侧发送图标,串口屏成功接收传回反馈,如下图所示:

  选择切页到第1页,串口指令为5a a5 07 10 70 00 00 01 3e c3,输入指令框后点击右侧发送图标,串口屏成功接收传回反馈,如下图所示:

  注意:具体指令内容可到 串口调试工具(UI_Debugger-II)使用说明中查看

  STM32F103系列MCU和乐升串口屏可以通过串口指令进行交互,下面演示如何进行代码编写实现串口屏的切页操作。

  通过 UI_Debugger 指令文档得到切页指令为 0x10 0x7000 0xXXXX,其中0x10为CMD写指令,0x7000为变量地址,代码中赋值给数组时需拆分为高位0x70和低位0x00,0xXXXX为切页的页数,如切页到第一页为0x0001,代码中赋值时也需要拆分为0x00和0x01。

  代码中给数组赋值切页指令时,数组组合顺序为:

  帧头:0xXXXX (2 byte)

  长度:0xXX (1 byte)

  CMD指令:0xXX (1 byte)

  变量地址:0x0000 ~ 0x5FFF (2 byte)

  写入内容:0xXXXX (2*n byte)

  CRC校验:0xXXXX (2 byte)

  长度根据CMD指令到CRC校验的长度确认。注意,对于串口写数据指令,单次发送的数据最多为 250 Bytes.

  CRC校验的计算代码如下:

  #include "stm32f10x.h"                  // Device header

  /*****************************CRC 校验*****************************/

  //高位字节的 CRC 值

  const uint8_t auchCRCHi[] = {

  0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40};

  //低位字节的 CRC 值

  const char auchCRCLo[] = {

  0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7, 0x05, 0xC5, 0xC4,

  0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, 0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3, 0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A, 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26, 0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5, 0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C, 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C, 0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83, 0x41, 0x81, 0x80, 0x40};

  unsigned short CRC16(uint8_t *puchMsg,uint16_t usDataLen)

  /* 函数以 unsigned short 类型返回 CRC */

  {

  uint8_t uchCRCHi = 0xFF ; /* CRC 的高字节初始化 */

  uint8_t uchCRCLo = 0xFF ; /* CRC 的低字节初始化 */

  uint16_t uIndex ; /* CRC 查询表索引 */

  while (usDataLen--) /* 完成整个报文缓冲区 */

  {

  uIndex = uchCRCLo ^ *puchMsg++ ; /* 计算 CRC */

  uchCRCLo = uchCRCHi ^ auchCRCHi[uIndex] ;

  uchCRCHi = auchCRCLo[uIndex] ;

  }

  return (uchCRCHi << 8 | uchCRCLo);

  演示使用的MCU型号为STM32F103RCT6,通过数据手册得到STM32F103RCT6的PA9、PA10引脚分别为USART1_TX和USART1_RX引脚。本次演示只进行写指令操作因此只需要使用PA9引脚与串口屏的RXD1引脚进行连接即可实现切页操作。

  UART串口输出配置如下:

  #include "stm32f10x.h"                  // Device header

  #include <stdio.h>

  #include <stdarg.h>

  void Uart_Init(void)

  {

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE)

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

  GPIO_InitTypeDef GPIO_InitStructure;

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;

  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

  GPIO_Init(GPIOA, &GPIO_InitStructure);

  USART_InitTypeDef USART_InitStructure;

  USART_InitStructure.USART_BaudRate = 115200;

  USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;

  USART_InitStructure.USART_Mode = USART_Mode_Tx;

  USART_InitStructure.USART_Parity = USART_Parity_No;

  USART_InitStructure.USART_StopBits = USART_StopBits_1;

  USART_InitStructure.USART_WordLength = USART_WordLength_8b;

  USART_Init(USART1, &USART_InitStructure);

  USART_Cmd(USART1, ENABLE);

  }

  uint16_t UART_SendByte(uint8_t Byte)

  {

  USART_SendData(USART1, Byte);

  while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);

  }

  uint16_t UART_SendData(uint8_t *send_buf, uint16_t Length)

  {

  uint16_t ret;

  uint32_t i;

  for (i = 0; i < Length; i ++)

  {

  ret = UART_SendByte(send_buf[i]);

  }

  return ret;

  }

  主函数编写如下:

  #include "stm32f10x.h"                  // Device header

  #include "Delay.h"

  #include "Uart.h"

  #include "CRC.h"

  uint8_t SCI_C0 = 0x5A;

  uint8_t SCI_C1 = 0xA5;

  uint8_t uart_data_buf[256];

  uint8_t len;

  uint8_t CRC_Enable_Flag = 1;

  uint8_t CRC_Feedback_Flag = 1;

  void LT_SendData_CRC_Frame(uint8_t *buf, uint8_t len1) //len1为CMD、变量地址和写入内容三者的长度之和

  {

  uint16_t TxToPc_crc;

  uint8_t crc[2] = {0};

  *(buf + 0) = SCI_C0;

  *(buf + 1) = SCI_C1;

  if (CRC_Enable_Flag)

  {

  TxToPc_crc = CRC16(buf + 3, len1);

  crc[0] = (uint8_t)(TxToPc_crc & 0x00ff);

  crc[1] = (uint8_t)((TxToPc_crc >> 8) & 0x00ff);

  len1 += 2;

  *(buf + len1 + 1) = crc[0];

  *(buf + len1 + 2) = crc[1];

  }

  *(buf + 2) = len1;

  len = len1 + 3;

  }

  int main()

  {

  Uart_Init();

  uint16_t ret;

  uint8_t cmd = 0x10;

  uart_data_buf[3] = cmd;

  uart_data_buf[4] = 0x70;

  uart_data_buf[5] = 0x00;

  uart_data_buf[6] = 0x00;

  uart_data_buf[7] = 0x01;

  while (1)

  {

  LT_SendData_CRC_Frame(uart_data_buf, 5);

  ret = UART_SendData(uart_data_buf, len);

  Delay_ms(1000);

  }

  }

  指令的填写在主函数进行,下图所示依次分别为帧头(0x5A,0xA5)、放置指令的数组、指令长度(len)、cmd指令、变量地址(0x7000)、写入数据(0x0001).

  此处演示为切页到页面1(0x0001),可根据需要自行修改。

  MCU与串口屏的连接需要将两边的 TXD 和 RXD 引脚交替链接,GND互连共地。

  串口调试工具UI_Debugger 必须使用 UI_Editor-II 压缩包解压出来的,位于软件目录下。

  打开软件后,其主界面如下图所示。具体软件版本以下载到的软件为主。软件主界面主要包括以下内容:

  Description:描述项,可在此处添加关于指令的描述。

  Select:勾选项,勾选后的指令可以进行 Send All、Star Loop 操作。

  CMD:指令项,10 表示写入数据、03 表示读取数据,长度为 1 Byte。

  Addr:地址项,目的变量地址,即对该地址读或者写。长度 2 Bytes。

  Data:数据项,需要写入的数据或者是操作的参数。长度是 2*n Bytes。

  CRC:校验码项,用于检验数据。长度 2 Bytes。(填写指令项、地址项和数据项后自动生成)。

  Send:发送按钮,点击发送此行的指令。

  收发指令都可以在此查看。黑色指令为发送出的指令,蓝色指令为接收到的指令。

  NO:信息排序。

  Header:帧头项。长度 2 Bytes。

  Length:长度项,指令长度。长度 2 Bytes。

  CMD:指令标志项。长度为 1 Byte。

  Addr:目标地址。

  Data:数据项,返回数据。长度是 2*n Bytes。若是上面发的是写指令则返回的数据为 0xFF,

  若上面发 的是读指令,则读反馈指令数据为 0xFF,读指令返回指令的数据为读指令的所需要的数据长度+变量地址 对应的数据。

  CRC:校验码项,用于检验数据。长度 2 Bytes。

  从左到右分别为,

  Com Port:选择通信端口。

  Baudrate:选择波特率,需要与工程设置的波特率对应,支持用户自定义波特率,如下图,选择 custom 选项可以填写用户自定义波特率。

  Parity:奇偶校验,需要与工程设置的 Parity 相同。

  CRC Enable:是否进行 CRC 校验,若工程勾选 No CRC,此处不用勾选。

  CMD Header:通信帧头,需要与工程设置的 User Start Bytes 相同。

  Open Com Port:开启端口。开启端口后才能发送指令。

  Send selected items:按照从上到下的顺序发送全部 select 项已勾选的指令

  Cycle Delay:循环发送时每次循环之间的时间间隔。

  Interval Time:循环时相邻指令之间发送的时间间隔。

  Auto Send:按照从上到下的顺序循环发送全部 select 项已勾选的指令。

  Clear Message:清空信息接收区的信息。

  Save Message:保存信息接收区的信息为 txt 文档。

  insert:在所选指令行上方插入一行空白的指令行。

  clone:在选中指令行的下方克隆一行选中的指令。

  delete:删除所选指令行。

  up:将所选指令行上移。

  down:将所选指令行下移。

  Delay:在所选指令行上方插入发送延时行(时间单位为 ms)。

  其步骤如下:

  (1)配置信息,选择对应端口、对应的波特率以及奇偶校验,确定帧头对应,勾选 CRC Enable,然后打开端口(Open Com Port)。

  (2)添加指令,双击指令行的单元格,对指令进行编辑。或点击右上角的载入已有的指令 txt 文件。

  (3)发送指令,单击发送,即可发送单条指令。

  (4)随后可在信息区获取到发送与接收指令的信息。

  其步骤如下:

  (1)右键调整指令上下位置(指令是按从上到下的顺序发送的)。

  (2)在 Select 项勾选所要发送的指令。

  (3)点击 Send selected items 或 Auto Send,即可一次发送多条指令与循环发送指令。

  (4)若要调整循环发送的时间间隔,可调整 Circle Delay 与 interval。

  (5)在 loop 模式下,可以自定义添加 delay 时间,其中++为 delay 标志(不可修改),可在 data 栏添加间隔时间(ms),希望启用该延时需勾选该行的 select 项。

  延时时间为 10 进制,单位为 ms。延时指令只由指令标志 “++” 和延时时间组成,其他部分不需要填写。延时指令穿插在两条正常指令之间,延时时间 + Interval Time 是两条指令之间的发送间隔。

  指令在指令文档内的格式如下表,可以在 UI_Debugger-II 内编辑后导出,也该指令可以在 txt 文档手动编辑, 需注意编辑指令文档时不可留下空白行。指令示例如下:

  点击 Save Message 可将信息区的指令收发记录保存为 txt 文档,文档内的指令均为完整指令,包括帧头、长度等部分。注意该文档不能重新导入 UI_Debugger-II 。文档内容示例如下: