前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >TKM32F499评估板串口通信学习与实践笔记

TKM32F499评估板串口通信学习与实践笔记

作者头像
杨源鑫
发布2020-05-21 16:23:31
1.7K0
发布2020-05-21 16:23:31
举报
文章被收录于专栏:嵌入式开发圈嵌入式开发圈

之前买了一块评估板,也写了相应的评测文章,链接如下:

TKM32F499高性能MCU评估板试用之万事开头难,先点个灯来压压惊!

我们在上面这篇文章已经领会了TKM32F499的强大了,接下来进入主题,串口通信实验。

1、TKM32F499通用异步收发器(UART)数据结构及参数描述

在UART库的头文件里,UART由一个结构体进行维护:

代码语言:javascript
复制
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 时钟频率)

代码语言:javascript
复制
X = SPBRG 寄存器值 (1 to 65535)

1.2 数据长度

代码语言:javascript
复制
/** @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 停止位

代码语言:javascript
复制
/** @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 校验位

代码语言:javascript
复制
/** @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 串口模式

代码语言:javascript
复制
/** @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 硬件流控

代码语言:javascript
复制
/** @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库文件中提供了一系列操作接口:

代码语言:javascript
复制
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

电路原理图如下:

根据原理图写出以下初始化函数:

代码语言:javascript
复制
/*用于调试打印*/
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。

编写重定向函数:

代码语言:javascript
复制
int fputc(int ch, FILE *f)
{
    while((UART4->CSR & 0x1) == 0) {}
    UART4->TDR = (u8) ch;
    return ch;
}

2、配置一路串口用于接收传感器数据(这里选择接UART1)

电路原理图如下:

实现代码逻辑:

代码语言:javascript
复制
/*用于接收传感器数据*/
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);
}

定义回调函数,编写接收逻辑,传感器用一个结构体进行维护:

代码语言:javascript
复制
#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;

接收回调函数处理:

代码语言:javascript
复制
//串口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:

在每次收到一次有效数据,即发生了一次串口接收中断,我们接收完数据后需要及时对中断标志进行清除,这里最重要的是第一位:

这些寄存器都是通过一个结构体进行维护:

代码语言:javascript
复制
/**
* @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标志就可以了:

代码语言:javascript
复制
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评估板例程及资料下载

代码语言:javascript
复制
链接:https://pan.baidu.com/s/1xujEO4vJ7i7UUK7v_fGNgw
提取码:g1y2
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-05-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 嵌入式云IOT技术圈 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1、TKM32F499通用异步收发器(UART)数据结构及参数描述
    • 1.1 波特率
      • 1.2 数据长度
        • 1.3 停止位
          • 1.4 校验位
            • 1.5 串口模式
              • 1.6 硬件流控
              • 2、TKM32F499通用异步收发器(UART)使用
              • TKM32F499评估板例程及资料下载
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档