当前位置:   article > 正文

K210 UART串口通信介绍与 STM32通信

K210 UART串口通信介绍与 STM32通信

目录

K210-UART串口通信相关函数:

使用K210串口的时候需要映射引脚:

K210与STM32串口通信 

发送单字节:

K210端

STM32端

发送数据包

K210端

STM32端 

K210的UART模块支持全双工通信,可以同时进行数据的发送和接收。在K210上使用UART串口通信,你可以连接外部设备,如传感器、显示器、WiFi模块等,实现数据的交换和控制。

K210-UART串口通信相关函数:

1.machine.UART():该函数用于初始化一个UART串口对象。你可以指定串口的编号(如UART1)、波特率、数据位、校验位、停止位、TX引脚和RX引脚等参数。

  1. import machine
  2. # 初始化串口
  3. uart = machine.UART(1, baudrate=115200, tx=12, rx=13)

在这个示例中,我们使用machine.UART()函数初始化了一个串口对象,指定了串口的编号(1)、波特率(115200)、TX引脚(12)和RX引脚(13)。

或者可以:

machine.UART(uart,baudrate,bits,parity,stop,timeout, read_buf_len)

machine.UART()函数是用于初始化一个UART串口对象的函数,它可以接受以下参数:

  • uart:串口编号,可以为1、2、3。
  • baudrate:波特率,用于指定串口通信的数据传输速率。
  • bits:数据位数,可以为5、6、7、8。
  • parity:校验位,可以为None、0、1、2。
  • stop:停止位,可以为1、2。
  • timeout:超时时间,单位为毫秒。
  • read_buf_len:读缓冲区长度,用于指定串口读取数据时的缓冲区大小。

其中,uart参数是必需的,其他参数都有默认值。下面分别介绍这些参数的含义和用法:

  • uart:串口编号,可以为1、2、3。如果你的开发板上有多个串口,需要指定使用哪个串口进行通信。
  • baudrate:波特率,用于指定串口通信的数据传输速率。常见的波特率有9600、115200等,需要根据实际情况进行设置。
  • bits:数据位数,可以为5、6、7、8。一般情况下使用8位数据位即可。
  • parity:校验位,可以为None、0、1、2。校验位用于检查数据传输中是否出现错误,一般情况下可以设置为None。
  • stop:停止位,可以为1、2。停止位用于指定每个数据帧的结束位置,一般情况下使用1个停止位即可。
  • timeout:超时时间,单位为毫秒。当读取串口数据时,如果在超时时间内没有读取到任何数据,则会返回None。
  • read_buf_len:读缓冲区长度,用于指定串口读取数据时的缓冲区大小。如果读取的数据量较大,可以适当增大该值,以避免数据丢失。


2.uart.write():该函数用于向串口发送数据。你可以发送字符串或者字节数据。

  1. # 发送数据
  2. uart.write('Hello, UART!')

3.uart.read():该函数用于从串口接收数据。它会阻塞程序直到接收到指定数量的数据或者超时

  1. # 接收数据
  2. data = uart.read(10)
  3. print(data)

这段代码从串口读取最多10个字节的数据,并将其打印出来。

4.uart.any():该函数用于检查串口是否有未读取的数据。如果有,返回值为True;否则返回False。

  1. # 检查是否有未读取的数据
  2. if uart.any():
  3. data = uart.read()
  4. print(data)

这段代码首先调用uart.any()函数检查串口是否有未读取的数据,如果有,则调用uart.read()函数将数据读取并打印出来。

5.uart.flush():该函数用于清空串口的缓冲区,将所有未读取的数据丢弃

使用K210串口的时候需要映射引脚

  1. # IO6→RX1,IO7→TX1
  2. fm.register(6, fm.fpioa.UART1_RX, force=True)
  3. fm.register(7, fm.fpioa.UART1_TX, force=True)

fm.register()函数是用于配置FPIOA(Flexible Peripheral I/O Assignments)的函数,它可以将指定的引脚与相应的功能进行绑定。

K210与STM32串口通信 

K210与STM32串口通信发送分为两种:一种是发送单字节,一种是发送数据包。因为发送的数据不一样,从而K210的代码和STM32的代码都是不一样的。

本篇文章只涉及K210发送给STM32。

发送单字节:

K210端

  1. from machine import UART, Timer
  2. from fpioa_manager import fm
  3. #映射串口引脚
  4. fm.register(6, fm.fpioa.UART1_RX, force=True)
  5. fm.register(7, fm.fpioa.UART1_TX, force=True)
  6. while True:
  7. text=uart.read() #读取数据
  8. if text: #如果读取到了数据
  9. uart.write('1')

STM32端

  1. void Usart3_Init(unsigned int baud)
  2. {
  3. GPIO_InitTypeDef gpio_initstruct;
  4. USART_InitTypeDef usart_initstruct;
  5. NVIC_InitTypeDef nvic_initstruct;
  6. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
  7. RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
  8. //PA2 TXD
  9. gpio_initstruct.GPIO_Mode = GPIO_Mode_AF_PP;
  10. gpio_initstruct.GPIO_Pin = GPIO_Pin_10;
  11. gpio_initstruct.GPIO_Speed = GPIO_Speed_50MHz;
  12. GPIO_Init(GPIOB, &gpio_initstruct);
  13. //PA3 RXD
  14. gpio_initstruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  15. gpio_initstruct.GPIO_Pin = GPIO_Pin_11;
  16. gpio_initstruct.GPIO_Speed = GPIO_Speed_50MHz;
  17. GPIO_Init(GPIOB, &gpio_initstruct);
  18. usart_initstruct.USART_BaudRate = baud;
  19. usart_initstruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  20. usart_initstruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
  21. usart_initstruct.USART_Parity = USART_Parity_No;
  22. usart_initstruct.USART_StopBits = USART_StopBits_1;
  23. usart_initstruct.USART_WordLength = USART_WordLength_8b;
  24. USART_Init(USART3, &usart_initstruct);
  25. USART_Cmd(USART3, ENABLE);
  26. USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);
  27. nvic_initstruct.NVIC_IRQChannel = USART2_IRQn;
  28. nvic_initstruct.NVIC_IRQChannelCmd = ENABLE;
  29. nvic_initstruct.NVIC_IRQChannelPreemptionPriority = 0;
  30. nvic_initstruct.NVIC_IRQChannelSubPriority = 1;
  31. NVIC_Init(&nvic_initstruct);
  32. }
  33. if(USART_ReceiveData(USART3)=='1')//K210
  34. {
  35. numbert++;
  36. }

发送数据包

K210端

  1. def str_int(data_str):
  2. bb = binascii.hexlify(data_str)
  3. bb = str(bb)[2:-1]
  4. #print(bb)
  5. #print(type(bb))
  6. hex_1 = int(bb[0])*16
  7. hex_2 = int(bb[1],16)
  8. return hex_1+hex_2
  9. def send_data(x,y,w,h,msg):
  10. start = 0x24
  11. end = 0x23
  12. length = 5
  13. class_num = 0x05 #例程编号
  14. class_group = 0xBB #例程组
  15. data_num = 0x00 #数据量
  16. fenge = 0x2c #逗号
  17. crc = 0 #校验位
  18. data = [] #数据组
  19. #参数都为0
  20. if x==0 and y==0 and w==0 and h ==0:
  21. pass
  22. else:
  23. #x(小端模式)
  24. low = x & 0xFF #低位
  25. high = x >> 8& 0xFF #高位
  26. data.append(low)
  27. data.append(fenge) #增加","
  28. data.append(high)
  29. data.append(fenge) #增加","
  30. #y(小端模式)
  31. low = y & 0xFF #低位
  32. high = y >> 8& 0xFF #高位
  33. data.append(low)
  34. data.append(fenge) #增加","
  35. data.append(high)
  36. data.append(fenge) #增加","
  37. #w(小端模式)
  38. low = w & 0xFF #低位
  39. high = w >> 8& 0xFF #高位
  40. data.append(low)
  41. data.append(fenge) #增加","
  42. data.append(high)
  43. data.append(fenge) #增加","
  44. #h(小端模式)
  45. low = h & 0xFF #低位
  46. high = h >> 8& 0xFF #高位
  47. data.append(low)
  48. data.append(fenge) #增加","
  49. data.append(high)
  50. data.append(fenge) #增加","
  51. if msg !=None:
  52. #msg
  53. for i in range(len(msg)):
  54. hec = str_int(msg[i])
  55. data.append(hec)
  56. data.append(fenge) #增加","
  57. #print(data)
  58. data_num = len(data)
  59. length += len(data)
  60. #print(length)
  61. send_merr = [length,class_num,class_group,data_num]
  62. for i in range(data_num):
  63. send_merr.append(data[i])
  64. #print(send_merr)
  65. #不加上CRC位,进行CRC运算
  66. for i in range(len(send_merr)):
  67. crc +=send_merr[i]
  68. crc = crc%256
  69. send_merr.insert(0,start) #插入头部
  70. send_merr.append(crc)
  71. send_merr.append(end)
  72. #print(send_merr)
  73. global send_buf
  74. send_buf = send_merr

首先是 str_int 函数,它的作用是将输入的字符串转换为整数。具体实现上,它使用了 Python 的标准库中的 binascii.hexlify 方法将输入的字符串 data_str 转换为十六进制表示的字节串,然后对于每一个字节,分别将其高四位和低四位转换成十进制数,并进行一定的运算,最终返回一个整数。

接下来是 send_data 函数,它的作用是组装一个特定格式的数据包。函数接受五个参数 x, y, w, h, msg,其中 x, y, w, h 是四个整数,msg 是一个字符串。根据这些参数,函数构建了一个包含起始标识、长度、例程编号、例程组、数据量、数据内容以及校验位的数据包。

在函数内部,首先定义了一些常量,如起始标识、结束标识、长度、例程编号、例程组等。然后根据传入的参数判断是否需要加入 x, y, w, h 这四个整数。如果这四个整数全部为 0,那么就不将它们加入数据包中,否则将它们按照小端模式(即低位在前、高位在后的顺序)加入到数据中。接下来是对传入的字符串 msg 进行处理,将其中每个字符转换为整数后加入数据中。

接着计算数据量和长度,并将所有数据组装成一个列表 send_merr。最后,计算校验位并将其加入到 send_merr 中,同时在开头和结尾分别加上起始标识和结束标识,最终得到一个完整的数据包。

STM32端 

  1. char buf_msg[100] = {'\0'};
  2. u8 new_flag = 0;
  3. u8 r_index = 0;
  4. u16 buf_crc = 0;
  5. u8 tou_flag = 0;
  6. u8 len_flag = 0;
  7. u8 buf_len = 0;
  8. char data[50];
  9. void recv_k210msg(uint8_t recv_msg)
  10. {
  11. if (recv_msg == '$')
  12. {
  13. new_flag = 1;
  14. }
  15. if (recv_msg == '#')
  16. {
  17. if (buf_len == r_index)
  18. {
  19. new_flag = 0;
  20. tou_flag = 0;
  21. len_flag = 0;
  22. buf_crc -= buf_msg[r_index - 1];
  23. buf_crc %= 256;
  24. if (buf_crc == buf_msg[r_index - 1])
  25. {
  26. deal_recvmsg();
  27. }
  28. else
  29. {
  30. r_index = 0;
  31. buf_crc = 0;
  32. }
  33. }
  34. }
  35. if (new_flag == 1)
  36. {
  37. if (recv_msg == '$' && tou_flag == 0)
  38. {
  39. tou_flag = 1;
  40. }
  41. else
  42. {
  43. buf_msg[r_index++] = recv_msg;
  44. buf_crc += recv_msg;
  45. if (len_flag == 0)
  46. {
  47. buf_len = buf_msg[0];
  48. len_flag = 1;
  49. }
  50. }
  51. }
  52. }
  53. void deal_recvmsg(void)
  54. {
  55. u8 index, data_i = 0;
  56. u8 eg_num = buf_msg[1];
  57. u8 number = buf_msg[3];
  58. u8 i_duo = 0;
  59. if (r_index != buf_len)
  60. {
  61. buf_len = 0;
  62. return;
  63. }
  64. for (index = 0; index < number; index++)
  65. {
  66. if (buf_msg[4 + index] == 0x2c && i_duo == 0)
  67. {
  68. i_duo = 1;
  69. continue;
  70. }
  71. data[data_i++] = buf_msg[4 + index];
  72. i_duo = 0;
  73. }
  74. buf_crc = 0;
  75. r_index = 0;
  76. memset(buf_msg, 0, sizeof(buf_msg));
  77. deal_data(eg_num);
  78. }
  79. void deal_data(u8 egnum)
  80. {
  81. u16 x, y, w, h;
  82. u8 msg[20] = {'\0'};
  83. u8 icopy = 0;
  84. u16 id = 999;
  85. switch (egnum)
  86. {
  87. case 1:
  88. case 5:
  89. case 6:
  90. x = data[1] << 8 | data[0];
  91. y = data[3] << 8 | data[2];
  92. w = data[5] << 8 | data[4];
  93. h = data[7] << 8 | data[6];
  94. break;
  95. case 2:
  96. case 3:
  97. x = data[1] << 8 | data[0];
  98. y = data[3] << 8 | data[2];
  99. w = data[5] << 8 | data[4];
  100. h = data[7] << 8 | data[6];
  101. while (*(data + 8 + icopy) != '\0')
  102. {
  103. msg[icopy] = *(data + 8 + icopy);
  104. icopy++;
  105. }
  106. break;
  107. case 4:
  108. x = data[1] << 8 | data[0];
  109. y = data[3] << 8 | data[2];
  110. w = data[5] << 8 | data[4];
  111. h = data[7] << 8 | data[6];
  112. id = data[8] << 8 | data[9];
  113. while (*(data + 10 + icopy) != '\0')
  114. {
  115. msg[icopy] = *(data + 10 + icopy);
  116. icopy++;
  117. }
  118. break;
  119. case 7:
  120. case 8:
  121. x = data[1] << 8 | data[0];
  122. y = data[3] << 8 | data[2];
  123. w = data[5] << 8 | data[4];
  124. h = data[7] << 8 | data[6];
  125. id = data[8];
  126. break;
  127. case 9:
  128. x = data[1] << 8 | data[0];
  129. y = data[3] << 8 | data[2];
  130. w = data[5] << 8 | data[4];
  131. h = data[7] << 8 | data[6];
  132. while (*(data + 8 + icopy) != '\0')
  133. {
  134. msg[icopy] = *(data + 8 + icopy);
  135. icopy++;
  136. }
  137. break;
  138. case 10:
  139. case 11:
  140. id = data[0];
  141. break;
  142. }
  143. k210_msg.class_n = egnum;
  144. k210_msg.x = x;
  145. k210_msg.y = y;
  146. k210_msg.w = w;
  147. k210_msg.h = h;
  148. k210_msg.id = id;
  149. strcpy((char*)k210_msg.msg_msg, (char*)msg);
  150. memset(data, 0, sizeof(data));
  151. }
  152. void USART2_IRQHandler(void)
  153. {
  154. uint8_t Rx2_Temp;
  155. if (USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)
  156. {
  157. Rx2_Temp = USART_ReceiveData(USART2);
  158. recv_k210msg(Rx2_Temp);
  159. }
  160. }
  1. recv_k210msg 函数用于接收 K210 模块传来的消息,并根据特定的起始符号 $ 和结束符号 # 进行消息解析。具体流程如下:

    • 当接收到 $ 符号时,表示开始接收新的消息,将 new_flag 置为 1。
    • 当接收到 # 符号时,表示消息接收完毕,进行消息处理。如果消息长度符合要求,计算消息校验和并调用 deal_recvmsg 进行处理。
    • 在接收到其他字符时,如果处于接收新消息状态,将字符存入缓冲区 buf_msg 中,并更新校验和 buf_crc
  2. deal_recvmsg 函数用于对接收到的消息进行处理,主要是根据消息类型和内容进行解析,并调用 deal_data 函数进行进一步处理。具体流程如下:

    • 根据消息中指定的格式提取数据,并调用 deal_data 函数进行处理。
    • 处理完成后,清空缓冲区 buf_msg 和相关标志位,以便接收下一条消息。
  3. deal_data 函数用于根据不同类型的消息对数据进行解析和处理。具体流程如下:

    • 根据消息的类型进行不同的数据解析操作,提取出消息中的有用信息,并赋值给 k210_msg 结构体。
    • 结构体 k210_msg 包含了消息的分类、位置信息、ID 信息以及消息内容。
    • 处理完成后,清空数据缓冲区 data

 有读者看到这里可能会想问,能不能用单字节的方式发送字符串,STM32中USART_ReceiveData(USART3)=='1'此处没法等于字符串。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/article/detail/56518
推荐阅读
相关标签
  

闽ICP备14008679号