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

简介: 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 时钟频率)

640.png

X = SPBRG 寄存器值 (1 to 65535)

640.jpg

640.png

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


电路原理图如下:

640.png640.png

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

/*用于调试打印*/
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。

640.png

编写重定向函数:

int fputc(int ch, FILE *f)
{
    while((UART4->CSR & 0x1) == 0) {}
    UART4->TDR = (u8) ch;
    return ch;
}

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


电路原理图如下:

640.png

实现代码逻辑:

/*用于接收传感器数据*/
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;
    }
}

接收这里主要用到串口的接收数据寄存器、中断状态寄存器、中断清除寄存器

640.png

接收数据在程序里就是一个RDR的寄存器。

640.png

其中在接收逻辑里需要去判断接收数据有效,最重要的是位1:

640.png

640.png

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

640.png

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

/**
* @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);
    }
}

最终效果,这里面还有我的其它逻辑:

640.png

640.jpg

如果对该评估板软件编程感兴趣的话,欢迎加我微信私聊交流~

TKM32F499评估板例程及资料下载

链接:https://pan.baidu.com/s/1xujEO4vJ7i7UUK7v_fGNgw
提取码:g1y2

或者后台回复TK499即可获取。

往期精彩

bin文件转换为hex文件C语言实现


最近收集的开源项目专栏(持续更新,收好车轮,方便造车)


推荐三个我工作中经常使用的驱动大全wiki(建议收藏并转发让更多人知道!)


变量命名还在谷歌百度翻译?OUT啦!分享一个我日常工作中常用的变量命名神器!

目录
相关文章
|
5月前
|
数据采集 数据可视化 数据管理
LabVIEW开发实验室超导体电流特性测试系统
LabVIEW开发实验室超导体电流特性测试系统
38 0
|
7月前
|
数据采集 存储 异构计算
LabVIEW编程LabVIEW开发高级数据采集技术 模拟波形的生成 例程与相关资料
LabVIEW编程LabVIEW开发高级数据采集技术 模拟波形的生成 例程与相关资料
60 9
|
7月前
|
传感器 数据采集 监控
基于LabVIEW的CAN通信系统开发案例
基于LabVIEW的CAN通信系统开发案例
78 3
|
编解码 算法 计算机视觉
学习红外成像仪开发注意要点
飞讯红外成像仪开发学习注意要点 红外成像仪是一种高级的光学设备,可用于探测、分析和显示红外辐射,它广泛应用于医学、军事、石油、矿产资源勘探等领域。红外成像仪的开发需要注意以下几个方面:
学习红外成像仪开发注意要点
|
7月前
|
安全
LabVIEW模拟化学反应器的工作
LabVIEW模拟化学反应器的工作
38 0
第六章 测验【嵌入式系统】
第六章 测验【嵌入式系统】
62 0
|
传感器 算法 IDE
LabVIEW和Arduino的巧妙结合(基础篇—1)
本专栏使用的单片机为:Arduino(本系列专栏使用Arduino UNO控制器),主要原因在于,Arduino简单易上手,老少皆宜,受众面广泛,使用Arduino作为下位机,LabVIEW作为上位机,独立开发者可以快捷开发出一套软硬件联控的演示系统。
|
存储 开发者 芯片
第五章 在线逻辑分析仪-SIGNALTAP
第五章 在线逻辑分析仪-SIGNALTAP
254 0
第五章 在线逻辑分析仪-SIGNALTAP
嵌入式小项目练习-光电设计竞赛-寻迹小车-01-赛题与流程图
嵌入式小项目练习-光电设计竞赛-寻迹小车-01-赛题与流程图
245 0
嵌入式小项目练习-光电设计竞赛-寻迹小车-01-赛题与流程图
|
传感器
嵌入式小项目练习-光电设计竞赛-寻迹小车-02-模块分析
嵌入式小项目练习-光电设计竞赛-寻迹小车-02-模块分析
169 0
嵌入式小项目练习-光电设计竞赛-寻迹小车-02-模块分析