赞
踩
目录
这篇文章是为了填上一篇k210的简单PID巡线埋下的坑,k210和STM32通过串口通信,我是采用数据包的形式发送数据的,因为K210发送的数据有几种,采用数据包的形式发送比较安全。
本文代码运行的平台是STM32F103C8T6和K210 Dock,只涉及到K210发送数据给STM32,stm32将接受到的数据显示到0.96寸OLED屏上。
STM32使用串口外设是USART1,由于只接受数据所以只用到I/O的PA10;K210的串口通信I/O可以自行定义,我使用的是靠5V口近的GPIO18。STM32上的3.3V电源和GND分别K210上的5V电源和GND连接。最后测试的时,直接用typ-c给K210供电,K210再给stm32供电。这个时候就有人会问了“为什么5V可以直接STM32供电?”因为一般的STM32F103C8T6最小系统上自带一块线性稳压器,它可以将K210的5V电源转化为3.3V给STM32芯片供电。(这只是为了方便测试,请检查你的STM32上是否有线性稳压器,若没有请单独供电)
K210 TX发送 | STM32F103 RX接收 |
GPIO 18 | PA 10 |
5V | 3.3V |
GND | GND |
- import time #延迟函数
- from machine import UART #串口库函数
- from fpioa_manager import fm # GPIO重定向函数
- fm.register(18, fm.fpioa.UART1_TX, force=True)
- uart_A = UART(UART.UART1, 115200, 8, 0, 1, timeout=1000, read_buf_len=4096)
在使用 uart1 前,我们需要使用 fm 来对芯片引脚进行映射和管理,将 I/O 18 设置为 uart1 的发送引脚。
波特率设置为115200,这里注意要和STM32设置的一样。8位数据宽度,不需要奇偶校验位,1位停止位。
timeout 为串口接收超时时间。read_buf_len :
串口接收缓冲,串口通过中断来接收数据,如果缓冲满了,将自动停止数据接收
- def sending_data(x,y,z):
- FH = bytearray([0x2C,0x12,x,y,z,0x5B])
- uart_A.write(FH);
传入你所需要发送的数据x、y、z,FH = bytearray([0x2C,0x12,x,y,z,0x5B])是将你的数据存入FH这个数组中。
uart_A.write用于使用串口发送数据,将这个数据包发送出去。
- Cx = 0
- Cy = 0
- Cz = 0
-
- while True:
-
- Cx+=1;
- Cy+=1;
- Cz+=1;
- sending_data(Cx,Cy,Cz)
- print("Cx:",Cx,"Cy",Cy,"Cz:",Cz)
- time.sleep_ms(1000)
该例子是让Cx、Cy、Cz每一秒自加一并发送给STM32。
程序运行后,串行终端每一秒打印一次
用一个CH340模块连接电脑读取一下串口数据。
电脑可以成功接收每组6个的数据包,每组数据中不变的就是帧头的两个2C,12和帧尾的5B。知道了这个格式,那么我们就可以开始编写STM32上的代码了。
本次程序在STM32上要实现的功能是接收数据后显示到OLED上,只需要初始化OLED和串口,在编写一下OLED显示的代码就行了。
- #include "stm32f10x.h" // Device header
- #include "OLED.h"
- #include "Serial.h"
- int main (void)
- {
- OLED_Init();
- Serial_Init();
- OLED_ShowString(1,1,"Cx:");
- OLED_ShowString(2,1,"Cy:");
- OLED_ShowString(3,1,"Cz:");
- while(1)
- {
- OLED_ShowNum(1,4,Cx,4);
- OLED_ShowNum(2,4,Cy,4);
- OLED_ShowNum(3,4,Cz,4);
- }
-
- }
这里的Cx、Cy、Cz我是直接在Serial.h中使用了extern 外部变量声明。
先进行串口初始化。
- #include "stm32f10x.h" // Device header
-
- uint8_t Cx,Cy,Cz;
-
- void Serial_Init(void)
- {
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
-
- //USART1_RX PA10
- GPIO_InitTypeDef GPIO_InitStructure;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
- 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_Rx;
- 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_ITConfig(USART1, USART_IT_RXNE, ENABLE);
-
- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
-
- NVIC_InitTypeDef NVIC_InitStructure;
- NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
- NVIC_Init(&NVIC_InitStructure);
-
- USART_Cmd(USART1, ENABLE);
- }
使用的是USART1,它对应的接收引脚为PA10,将PA10设置为GPIO_Mode_IPU(输入上拉)模式,波特率设置为115200,8位数据宽度,不需要奇偶校验位,1位停止位,要和K210一致。再初始化串口中断并使能中断。
接收数据包的逻辑编写
- void USART1_IRQHandler(void)
- {
- u8 com_data;
- u8 i;
- static u8 RxCounter1=0;
- static u16 RxBuffer1[6]={0};
- static u8 RxState = 0;
-
- if( USART_GetITStatus(USART1,USART_IT_RXNE)!=RESET) //接收中断
- {
-
- USART_ClearITPendingBit(USART1,USART_IT_RXNE); //清除中断标志
- com_data = USART_ReceiveData(USART1);
- if(RxState==0&&com_data==0x2C) //0x2c帧头
- {
-
- RxState=1;
- RxBuffer1[RxCounter1++]=com_data;
- }
-
- else if(RxState==1&&com_data==0x12) //0x12帧头
- {
- RxState=2;
- RxBuffer1[RxCounter1++]=com_data;
- }
-
- else if(RxState==2)
- {
- RxBuffer1[RxCounter1++]=com_data;
-
- if(RxCounter1==6 && com_data == 0x5B) //RxBuffer1接受满了,接收数据结束
- {
-
- Cx=RxBuffer1[RxCounter1-4];
- Cy=RxBuffer1[RxCounter1-3];
- Cz=RxBuffer1[RxCounter1-2];
- RxCounter1 = 0;
- RxState = 0;
- }
- else if(RxCounter1 > 6) //接收异常
- {
- RxState = 0;
- RxCounter1=0;
- for(i=0;i<6;i++)
- {
- RxBuffer1[i]=0x00; //将存放数据数组清零
- }
-
- }
- }
- else //接收异常
- {
- RxState = 0;
- RxCounter1=0;
- for(i=0;i<6;i++)
- {
- RxBuffer1[i]=0x00; //将存放数据数组清零
- }
- }
-
- }
-
- }
com_data 用于读取STM32串口收到的数据,这个数据会被下一个数据掩盖,所以要将它用一个数组储存起来。
RxBuffer1[6]={0} 定义一个6个成员的数组,可以存放6个数据,刚好放下一个数据包。
RxCounter1 用来计次,让RXBufeer1这个数组能依次存入数据包。
RxState 接收状态,判断程序应该接收第一个帧头、第二个帧头、数据或帧尾。
com_data = USART_ReceiveData(USART1); 读取 将串口接收到的数据。
if(RxState==0&&com_data==0x2C) //0x2c帧头
{
RxState=1;
RxBuffer1[RxCounter1++]=com_data;
}
当RXState处于0时,为接收帧头1模式。若接收到帧头1(0x2C),将RXState置1,切换到接收帧头2模式,并将帧头1存入RxBuffer1[0]的位置,RxCounter1加一。
else if(RxState==1&&com_data==0x12) //0x12帧头
{
RxState=2;
RxBuffer1[RxCounter1++]=com_data;
}
当RXState处于1时,为接收帧头2模式。若接收到帧头2(0x12),将RXState置2,切换到保存数据模式,并将帧头2存入RxBuffer1[1]的位置,RxCounter1加一。
else if(RxState==2)
{
RxBuffer1[RxCounter1++]=com_data;if(RxCounter1==6 && com_data == 0x5B) //RxBuffer1接受满了,接收数据束
{
Cx=RxBuffer1[RxCounter1-4];
Cy=RxBuffer1[RxCounter1-3];
Cz=RxBuffer1[RxCounter1-2];
RxCounter1 = 0;
RxState = 0;
}}
当RXState处于2时,为保存数据模式。RxBuffer1[]将接收到的数据依次存入RxBuffer1[2]、RxBuffer1[3]、RxBuffer1[4]、RxBuffer1[5]中。当接收到第六位数据时,进行判断是否为帧尾(0x5B),若是帧尾分别保存数据RxBuffer1[2]、RxBuffer1[3]、RxBuffer1[4]到Cx、Cy、 Cz中。
else if(RxCounter1 > 6)
{
RxState = 0;
RxCounter1=0;
for(i=0;i<6;i++)
{
RxBuffer1[i]=0x00; //将存放数据数组清零
}
}
若是不是帧尾帧尾将会把RxState、RxCounter1和RxBuffer1[]全部置零做接收异常处理。
else //接收异常
{
RxState = 0;
RxCounter1=0;
for(i=0;i<6;i++)
{
RxBuffer1[i]=0x00; //将存放数据数组清零
}
}}
若没接收到帧头1(0x2C)和帧头2(0x12),将会把RxState、RxCounter1和RxBuffer1[]全部置零做接收异常处理。
OLED显示Cx、Cy、 Cz每秒加一
K210
- # Untitled - By: User - 周日 4月 23 2023
- import time
- from machine import UART #串口库函数
- from fpioa_manager import fm # GPIO重定向函数
-
- fm.register(18, fm.fpioa.UART1_TX, force=True)
- uart_A = UART(UART.UART1, 115200, 8, 0, 1, timeout=1000, read_buf_len=4096)
-
-
- def sending_data(x,y,z):
- FH = bytearray([0x2C,0x12,x,y,z,0x5B])
- uart_A.write(FH);
-
- Cx = 0
- Cy = 0
- Cz = 0
-
- while True:
-
- Cx+=1;
- Cy+=1;
- Cz+=1;
- sending_data(Cx,Cy,Cz)
- print("Cx:",Cx,"Cy",Cy,"Cz:",Cz)
- time.sleep_ms(1000)
STM32
目前已经讲述了STM32驱动A4950、K210的简单PID循迹,但要做出一辆循迹小车还是不够的,还需要PID速度环去调节小车的速度,才能完成一个完整的循迹小车,有时间我会更新后面的代码。
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。