TKM32F499评估板串口通信学习与实践笔记
扫描二维码
随时随地手机看文章
之前买了一块评估板,也写了相应的评测文章,链接如下:
TKM32F499高性能MCU评估板试用之万事开头难,先点个灯来压压惊!
我们在上面这篇文章已经领会了TKM32F499的强大了,接下来进入主题,串口通信实验。
1、TKM32F499通用异步收发器(UART)数据结构及参数描述
在UART库的头文件里,UART由一个结构体进行维护:
typedef struct
{
//波特率
uint32_t UART_BaudRate;
//数据长度
uint16_t UART_WordLength;
//停止位
uint16_t UART_StopBits;
//校验位
uint16_t UART_Parity;
//模式
uint16_t UART_Mode;
//硬件流控
uint16_t UART_HardwareFlowControl;
} UART_InitTypeDef;
1.1 波特率
波特率是由波特率发生器产生的,这是一个专用16位的,UART波特率寄存器控制16 位自由运转的计数器的计数周期。提供期望的波特率和 Fosc(APB 时钟频率)
X = SPBRG 寄存器值 (1 to 65535)
1.2 数据长度
/** @defgroup UART_Word_Length
* @{
*/
#define UART_WordLength_5b ((uint16_t)0x0000)
#define UART_WordLength_6b ((uint16_t)0x0010)
#define UART_WordLength_7b ((uint16_t)0x0020)
#define UART_WordLength_8b ((uint16_t)0x0030)
一般在工程应用中都是选择UART_WordLength_8b
1.3 停止位
/** @defgroup UART_Stop_Bits
* @{
*/
#define UART_StopBits_1 ((uint16_t)0x0000)
#define UART_StopBits_2 ((uint16_t)0x0004)
#define IS_UART_STOPBITS(STOPBITS) (((STOPBITS) == UART_StopBits_1) || \
((STOPBITS) == UART_StopBits_2))
一般在工程应用中都是选择UART_StopBits_1
1.4 校验位
/** @defgroup UART_Parity
* @{
*/
#define UART_Parity_No ((uint16_t)0x0000)
#define UART_Parity_Even ((uint16_t)0x0003)
#define UART_Parity_Odd ((uint16_t)0x0001)
#define IS_UART_PARITY(PARITY) (((PARITY) == UART_Parity_No) || \
((PARITY) == UART_Parity_Even) || \
((PARITY) == UART_Parity_Odd))
一般在工程应用中都是选择UART_Parity_No(无校验)
1.5 串口模式
/** @defgroup UART_Mode
* @{
*/
#define UART_Mode_Rx ((uint16_t)0x0008)
#define UART_Mode_Tx ((uint16_t)0x0010)
#define IS_UART_MODE(MODE) ((((MODE) & (uint16_t)0xFFE7) == 0x00) && ((MODE) != (uint16_t)0x00))
这个指的是当前串口为可接收还是可发送,可以同时拥有,也可以单个选择,具体根据项目需求制定。
1.6 硬件流控
/** @defgroup UART_Hardware_Flow_Control
* @{
*/
#define UART_HardwareFlowControl_None ((uint16_t)0x0000)
#define IS_UART_HARDWARE_FLOW_CONTROL(CONTROL)\
(((CONTROL) == UART_HardwareFlowControl_None) || \
((CONTROL) == UART_HardwareFlowControl_RTS) || \
((CONTROL) == UART_HardwareFlowControl_CTS) || \
((CONTROL) == UART_HardwareFlowControl_RTS_CTS))
一般工程应用中会直接将这个设置为UART_HardwareFlowControl_None 在HAL_uart.h库文件中提供了一系列操作接口:
void UART_DeInit(UART_TypeDef* UARTx);
void UART_Init(UART_TypeDef* UARTx, UART_InitTypeDef* UART_InitStruct);
void UART_StructInit(UART_InitTypeDef* UART_InitStruct);
void UART_Cmd(UART_TypeDef* UARTx, FunctionalState NewState);
void UART_ITConfig(UART_TypeDef* UARTx, uint16_t UART_IT, FunctionalState NewState);
void UART_DMACmd(UART_TypeDef* UARTx, uint16_t UART_DMAReq, FunctionalState NewState);
void UART_SendData(UART_TypeDef* UARTx, uint16_t Data);
uint16_t UART_ReceiveData(UART_TypeDef* UARTx);
FlagStatus UART_GetFlagStatus(UART_TypeDef* UARTx, uint16_t UART_FLAG);
void UART_ClearFlag(UART_TypeDef* UARTx, uint16_t UART_FLAG);
ITStatus UART_GetITStatus(UART_TypeDef* UARTx, uint16_t UART_IT);
void UART_ClearITPendingBit(UART_TypeDef* UARTx, uint16_t UART_IT);
跟STM32操作类似,我们直接调就完了,不明白的地方直接看数据手册解决!
2、TKM32F499通用异步收发器(UART)使用
使用串口功能之前,还是一样,先确定我这边的需求,我这边需要接收一串以下格式的数据:
序号 信号值 差值\r\n
这个数据是我手上传感器发过来的数据,然后我用TKM32F499进行接收。
1、配置一路串口用于printf输出,这里选择UART4
电路原理图如下:
根据原理图写出以下初始化函数:
/*用于调试打印*/
void Uart4Init(int BaudRate)
{
UART_InitTypeDef UART_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOD, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出
GPIO_Init(GPIOD, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉输入
GPIO_Init(GPIOD, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOD, GPIO_Pin_6 | GPIO_Pin_7, GPIO_AF_UART_2345);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_UART4, ENABLE);
UART_InitStructure.UART_BaudRate = BaudRate; //波特率
UART_InitStructure.UART_WordLength = UART_WordLength_8b;//数据位
UART_InitStructure.UART_StopBits = UART_StopBits_1;//停止位
UART_InitStructure.UART_Parity = UART_Parity_No ;
UART_InitStructure.UART_Mode = UART_Mode_Rx | UART_Mode_Tx;//输入输出模式
UART_InitStructure.UART_HardwareFlowControl = UART_HardwareFlowControl_None;
UART_Init(UART4, &UART_InitStructure);
UART_Cmd(UART4, ENABLE); //UART 模块使能
UART_ClearITPendingBit(UART4, 0xff);
}
调试不用增加接收功能,所以不需要写接收回调函数,但需要写一个串口重定向,并把微库勾上才能使用printf。
编写重定向函数:
int fputc(int ch, FILE *f)
{
while((UART4->CSR & 0x1) == 0) {}
UART4->TDR = (u8) ch;
return ch;
}
2、配置一路串口用于接收传感器数据(这里选择接UART1)
电路原理图如下:
实现代码逻辑:
/*用于接收传感器数据*/
void Uart1Init(int BaudRate)
{
UART_InitTypeDef UART_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //uart1_tx pa9
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 推挽复用输出
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //uart1_rx pa10
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉输入
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOA, GPIO_Pin_9 | GPIO_Pin_10, GPIO_AF_UART_1); //PA9、PA10复用为串口1
GPIO_PinAFConfig(GPIOA, GPIO_Pin_15, GPIO_AF_GPIO); //PA15复用为普通GPIO
RCC_APB2PeriphClockCmd(RCC_APB2Periph_UART1, ENABLE);
UART_InitStructure.UART_BaudRate = BaudRate; //波特率
UART_InitStructure.UART_WordLength = UART_WordLength_8b;//数据位
UART_InitStructure.UART_StopBits = UART_StopBits_1;//停止位
UART_InitStructure.UART_Parity = UART_Parity_No ;
UART_InitStructure.UART_Mode = UART_Mode_Rx | UART_Mode_Tx;//输入输出模式
UART_InitStructure.UART_HardwareFlowControl = UART_HardwareFlowControl_None;
UART_Init(UART1, &UART_InitStructure);
UART_Cmd(UART1, ENABLE); //UART 模块使能
UART_ClearITPendingBit(UART1, 0xff);
//这里需要进行接收,所以要打开接收中断
UART_ITConfig(UART1, UART_IT_RXIEN, ENABLE);//使能接收中断
NVIC_SetPriority(UART1_IRQn, 3);
NVIC_EnableIRQ(UART1_IRQn);
}
定义回调函数,编写接收逻辑,传感器用一个结构体进行维护:
#define SENSOR_BUFFER_SIZE 42
typedef struct
{
uint8_t BufferReady;
uint16_t Sensor_rx_count ;
uint8_t SensorRxBuffer[SENSOR_BUFFER_SIZE];
uint8_t SensorTxBuffer[SENSOR_BUFFER_SIZE];
} Sensor_HandleTypeDef;
extern Sensor_HandleTypeDef Sensor;
接收回调函数处理:
//串口1接收中断处理函数,打印传感器数据
void UART1_IRQHandler(void)
{
u8 ucCh;
/*当ISR位1为1时,表示接收到有效字节数据*/
if(UART1->ISR & (1 << 1))
{
/*接收到了一个字节的数据*/
ucCh = UART1->RDR;
if('\n' != ucCh)
{
Sensor.SensorRxBuffer[Sensor.Sensor_rx_count++] = ucCh ;
}
else
{
/*如果接收的是\n,则上一个接收的数据为'\r'结束*/
if('\r' == Sensor.SensorRxBuffer[Sensor.Sensor_rx_count - 1])
{
/*添加结束符*/
Sensor.SensorRxBuffer[Sensor.Sensor_rx_count - 1] = 0x00 ;
/*接收计数清0*/
Sensor.Sensor_rx_count = 0 ;
Sensor.BufferReady = 1 ;
}
}
/*清除中断接收标志*/
UART1->ICR |= 1 << 1;
}
}
接收这里主要用到串口的接收数据寄存器、中断状态寄存器、中断清除寄存器
接收数据在程序里就是一个RDR的寄存器。其中在接收逻辑里需要去判断接收数据有效,最重要的是位1:
在每次收到一次有效数据,即发生了一次串口接收中断,我们接收完数据后需要及时对中断标志进行清除,这里最重要的是第一位:这些寄存器都是通过一个结构体进行维护:
/**
* @brief Universal Synchronous Asynchronous Receiver Transmitter
*/
typedef struct
{
__IO uint32_t TDR;
__IO uint32_t RDR;
__IO uint32_t CSR;
__IO uint32_t ISR;
__IO uint32_t IER;
__IO uint32_t ICR;
__IO uint32_t GCR;
__IO uint32_t CCR;
__IO uint32_t BRR;
__IO uint32_t FRABRG;
} UART_TypeDef;
具体使用方法请参考TKM32F499的芯片数据手册,当然如果不习惯用寄存器进行操作,也可以使用好炬润官方的HAL lib,调用相应的库函数。串口应用逻辑编写完毕以后,接下来我们在主函数的循环内判断BufferReady标志就可以了:
while(1)
{
if(1 == Sensor.BufferReady)
{
Sensor.BufferReady = 0;
/*解析传感器数据*/
Sensor_Detect_Process(Sensor.SensorRxBuffer);
printf("流水号:%d 信号值:%d 差值:%d\n",sensor_data.Sensor_Serial_Number
,sensor_data.Sensor_TP1_Singal_Value,sensor_data.Sensor_TP1_Devalue
);
LCD_PutString(100, 60, (char *)Sensor.SensorRxBuffer, Red, Yellow, 1);
status = !status;
GPIO_WriteBit(GPIOA,GPIO_Pin_15,status);
}
}
最终效果,这里面还有我的其它逻辑:
如果对该评估板软件编程感兴趣的话,欢迎加我微信私聊交流~
TKM32F499评估板例程及资料下载
链接:https://pan.baidu.com/s/1xujEO4vJ7i7UUK7v_fGNgw
提取码:g1y2
或者后台回复TK499即可获取。
往期精彩
bin文件转换为hex文件C语言实现
最近收集的开源项目专栏(持续更新,收好车轮,方便造车)
推荐三个我工作中经常使用的驱动大全wiki(建议收藏并转发让更多人知道!)
变量命名还在谷歌百度翻译?OUT啦!分享一个我日常工作中常用的变量命名神器!
若觉得本次分享的文章对您有帮助,随手点[在看]
并转发分享,也是对我的支持。
免责声明:本文内容由21ic获得授权后发布,版权归原作者所有,本平台仅提供信息存储服务。文章仅代表作者个人观点,不代表本平台立场,如有问题,请联系我们,谢谢!