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引脚等参数。++

python 复制代码
import machine

# 初始化串口
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():该函数用于向串口发送数据。你可以发送字符串或者字节数据。++

python 复制代码
# 发送数据
uart.write('Hello, UART!')

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

python 复制代码
# 接收数据
data = uart.read(10)
print(data)

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

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

python 复制代码
# 检查是否有未读取的数据
if uart.any():
    data = uart.read()
    print(data)

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

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

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

python 复制代码
# IO6→RX1,IO7→TX1
fm.register(6, fm.fpioa.UART1_RX, force=True)
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端

python 复制代码
from machine import UART, Timer
from fpioa_manager import fm

#映射串口引脚
fm.register(6, fm.fpioa.UART1_RX, force=True)
fm.register(7, fm.fpioa.UART1_TX, force=True)
while True:
    text=uart.read() #读取数据

    if text: #如果读取到了数据
        uart.write('1')

STM32端

python 复制代码
void Usart3_Init(unsigned int baud)
{
    GPIO_InitTypeDef gpio_initstruct;
	USART_InitTypeDef usart_initstruct;
	NVIC_InitTypeDef nvic_initstruct;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
	
	//PA2	TXD
	gpio_initstruct.GPIO_Mode = GPIO_Mode_AF_PP;
	gpio_initstruct.GPIO_Pin = GPIO_Pin_10;
	gpio_initstruct.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &gpio_initstruct);
	
	//PA3	RXD
	gpio_initstruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	gpio_initstruct.GPIO_Pin = GPIO_Pin_11;
	gpio_initstruct.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &gpio_initstruct);
	
	usart_initstruct.USART_BaudRate = baud;
	usart_initstruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;		
	usart_initstruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;						
	usart_initstruct.USART_Parity = USART_Parity_No;									
	usart_initstruct.USART_StopBits = USART_StopBits_1;								
	usart_initstruct.USART_WordLength = USART_WordLength_8b;							
	USART_Init(USART3, &usart_initstruct);
	USART_Cmd(USART3, ENABLE);	
	USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);									
	nvic_initstruct.NVIC_IRQChannel = USART2_IRQn;
	nvic_initstruct.NVIC_IRQChannelCmd = ENABLE;
	nvic_initstruct.NVIC_IRQChannelPreemptionPriority = 0;
	nvic_initstruct.NVIC_IRQChannelSubPriority = 1;
	NVIC_Init(&nvic_initstruct);

}
if(USART_ReceiveData(USART3)=='1')//K210
{
        numbert++;
}

发送数据包

K210端

python 复制代码
def str_int(data_str):
    bb = binascii.hexlify(data_str)
    bb = str(bb)[2:-1]
    #print(bb)
    #print(type(bb))
    hex_1 = int(bb[0])*16
    hex_2 = int(bb[1],16)
    return hex_1+hex_2


def send_data(x,y,w,h,msg):
    start = 0x24
    end = 0x23
    length = 5
    class_num = 0x05 #例程编号
    class_group = 0xBB #例程组
    data_num = 0x00 #数据量
    fenge = 0x2c #逗号
    crc = 0 #校验位
    data = [] #数据组

    #参数都为0
    if x==0 and y==0 and w==0 and h ==0:
        pass
    else:
        #x(小端模式)
        low = x & 0xFF #低位
        high = x >> 8& 0xFF #高位
        data.append(low)
        data.append(fenge) #增加","
        data.append(high)
        data.append(fenge) #增加","

        #y(小端模式)
        low = y & 0xFF #低位
        high = y >> 8& 0xFF #高位
        data.append(low)
        data.append(fenge) #增加","
        data.append(high)
        data.append(fenge) #增加","

        #w(小端模式)
        low = w & 0xFF #低位
        high = w >> 8& 0xFF #高位
        data.append(low)
        data.append(fenge) #增加","
        data.append(high)
        data.append(fenge) #增加","

        #h(小端模式)
        low = h & 0xFF #低位
        high = h >> 8& 0xFF #高位
        data.append(low)
        data.append(fenge) #增加","
        data.append(high)
        data.append(fenge) #增加","

    if msg !=None:
        #msg
        for i in range(len(msg)):
            hec = str_int(msg[i])
            data.append(hec)
            data.append(fenge) #增加","
        #print(data)

    data_num = len(data)
    length += len(data)
    #print(length)

    send_merr = [length,class_num,class_group,data_num]
    for i in range(data_num):
        send_merr.append(data[i])
    #print(send_merr)

    #不加上CRC位,进行CRC运算
    for i in range(len(send_merr)):
        crc +=send_merr[i]
    crc = crc%256

    send_merr.insert(0,start) #插入头部
    send_merr.append(crc)
    send_merr.append(end)

    #print(send_merr)
    global send_buf
    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端

python 复制代码
char buf_msg[100] = {'\0'};
u8 new_flag = 0;
u8 r_index = 0;
u16 buf_crc = 0;
u8 tou_flag = 0;
u8 len_flag = 0;
u8 buf_len = 0;
char data[50];

void recv_k210msg(uint8_t recv_msg)
{
    if (recv_msg == '$')
    {
        new_flag = 1;
    }

    if (recv_msg == '#')
    {
        if (buf_len == r_index)
        {
            new_flag = 0;
            tou_flag = 0;
            len_flag = 0;

            buf_crc -= buf_msg[r_index - 1];
            buf_crc %= 256;

            if (buf_crc == buf_msg[r_index - 1])
            {
                deal_recvmsg();
            }
            else
            {
                r_index = 0;
                buf_crc = 0;
            }
        }
    }

    if (new_flag == 1)
    {
        if (recv_msg == '$' && tou_flag == 0)
        {
            tou_flag = 1;
        }
        else
        {
            buf_msg[r_index++] = recv_msg;
            buf_crc += recv_msg;
            if (len_flag == 0)
            {
                buf_len = buf_msg[0];
                len_flag = 1;
            }
        }
    }
}

void deal_recvmsg(void)
{
    u8 index, data_i = 0;
    u8 eg_num = buf_msg[1];
    u8 number = buf_msg[3];
    u8 i_duo = 0;
  
    if (r_index != buf_len)
    {
        buf_len = 0;
        return;
    }

    for (index = 0; index < number; index++)
    {
        if (buf_msg[4 + index] == 0x2c && i_duo == 0)
        {
            i_duo = 1;
            continue;
        }
        data[data_i++] = buf_msg[4 + index];
        i_duo = 0;
    }

    buf_crc = 0;
    r_index = 0;

    memset(buf_msg, 0, sizeof(buf_msg));
    deal_data(eg_num);
}

void deal_data(u8 egnum)
{
    u16 x, y, w, h;
    u8 msg[20] = {'\0'};
    u8 icopy = 0;
    u16 id = 999;
    switch (egnum)
    {
        case 1:
        case 5:
        case 6:
            x = data[1] << 8 | data[0];
            y = data[3] << 8 | data[2];
            w = data[5] << 8 | data[4];
            h = data[7] << 8 | data[6];
            break;

        case 2:
        case 3:
            x = data[1] << 8 | data[0];
            y = data[3] << 8 | data[2];
            w = data[5] << 8 | data[4];
            h = data[7] << 8 | data[6];
            while (*(data + 8 + icopy) != '\0')
            {
                msg[icopy] = *(data + 8 + icopy);
                icopy++;
            }
            break;

        case 4:
            x = data[1] << 8 | data[0];
            y = data[3] << 8 | data[2];
            w = data[5] << 8 | data[4];
            h = data[7] << 8 | data[6];
            id = data[8] << 8 | data[9];

            while (*(data + 10 + icopy) != '\0')
            {
                msg[icopy] = *(data + 10 + icopy);
                icopy++;
            }

            break;

        case 7:
        case 8:
            x = data[1] << 8 | data[0];
            y = data[3] << 8 | data[2];
            w = data[5] << 8 | data[4];
            h = data[7] << 8 | data[6];
            id = data[8];

            break;

        case 9:
            x = data[1] << 8 | data[0];
            y = data[3] << 8 | data[2];
            w = data[5] << 8 | data[4];
            h = data[7] << 8 | data[6];
            while (*(data + 8 + icopy) != '\0')
            {
                msg[icopy] = *(data + 8 + icopy);
                icopy++;
            }
            break;

        case 10:
        case 11:
            id = data[0];
            break;
    }
    
    k210_msg.class_n = egnum;
    k210_msg.x = x;
    k210_msg.y = y;
    k210_msg.w = w;
    k210_msg.h = h;
    k210_msg.id = id;
    strcpy((char*)k210_msg.msg_msg, (char*)msg);

    memset(data, 0, sizeof(data));
}
void USART2_IRQHandler(void)
{
	uint8_t Rx2_Temp;
	if (USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)
	{
		Rx2_Temp = USART_ReceiveData(USART2);
		recv_k210msg(Rx2_Temp);
	}
}
  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'此处没法等于字符串。

相关推荐
森焱森31 分钟前
无人机三轴稳定控制(2)____根据目标俯仰角,实现俯仰稳定化控制,计算出升降舵输出
c语言·单片机·算法·架构·无人机
白鱼不小白34 分钟前
stm32 USART串口协议与外设(程序)——江协教程踩坑经验分享
stm32·单片机·嵌入式硬件
S,D1 小时前
MCU引脚的漏电流、灌电流、拉电流区别是什么
驱动开发·stm32·单片机·嵌入式硬件·mcu·物联网·硬件工程
芯岭技术4 小时前
PY32F002A单片机 低成本控制器解决方案,提供多种封装
单片机·嵌入式硬件
youmdt5 小时前
Arduino IDE ESP8266连接0.96寸SSD1306 IIC单色屏显示北京时间
单片机·嵌入式硬件
嘿·嘘5 小时前
第七章 STM32内部FLASH读写
stm32·单片机·嵌入式硬件
Meraki.Zhang5 小时前
【STM32实践篇】:I2C驱动编写
stm32·单片机·iic·驱动·i2c
几个几个n7 小时前
STM32-第二节-GPIO输入(按键,传感器)
单片机·嵌入式硬件
Despacito0o10 小时前
ESP32-s3摄像头驱动开发实战:从零搭建实时图像显示系统
人工智能·驱动开发·嵌入式硬件·音视频·嵌入式实时数据库
门思科技11 小时前
设计可靠 LoRaWAN 设备时需要考虑的关键能力
运维·服务器·网络·嵌入式硬件·物联网