GD 32串口字节发送详解
1.0 GD 32 串口通信基础知识
串行通信与并行通信
第一个是并行通信的原理图,第二个是串行通信的原理图,并行通信表示多个通道同时发送和接收数据,串行通信表示只有一条数据线,数据是从数据线上一位一位的发送。
常见的通信协议主要有IIC,USART,SPI,CAN总线【CAN是一种差分数据线】
同步通信和异步通信的概念:同步指的是通信双方约定特定的时钟传输频率,这个频率是比较严格的,通信双发必须严格的按照这个频率进行数据传输。
异步通信:通信双方有自己的数据线和时钟线无需约定特定的通信频率进行数据的传输,但是需要按照协议的规定进行数据的传输和发送。
比如:串口通信就是开始时高电平,当出现低电平的时候就是告诉单片机我要开始数据的发送了,之后通过电平的高低起伏一个bit一个bit的将数据发送出去,其中还可以再发送字节的后面添加一个校验问,如CRC校验,奇偶校验等,结束时将电平拉高,方便后续字节的发送。
串口有一个发送数据叫TXD 主要是用于数据的发送,有一个RXD主要是用于数据的接收,对应上面数据发送和接收的过程。
2.0 单工,双工,半双工的概念
知道了解这个概念很多地方都会讲到,以下直接贴图的方式进行展示
3.0 串口的几种常见的电器协议
第一种是TTL电平,3.3V或者5V表示高电平,0V表示低电平,TTL电平适合用于短距离的通信
以上是RS232电平 -3~-15表示高电平,3 ~ 15V 表示低电平0,最大的通信距离是15m
4.0 ARM 单片机硬件结构讲解
5.0 单片机串口的硬件结构
串口的波特率需要按自己的实际使用情况进行选择,51单片机串口的波特率需要自己计算
目前我使用的这款单片机串口的复用使用情况
TBE 标志位为1的时候表示数据寄存器空,0的时候表示数据寄存器里面还有数据,TC标志位用于发送移位寄存器。TC = 1 的时候表示移位寄存器中有数据,0表示移寄存器中没有数据,RNBE用于接首的场景,只要寄存器是空的RNBE标志位就是1,如果有数据就是0,通过这些标志位告诉CPU是否进行下一步的动作。
6.0 串口通信的差错校验方式
串口发送接收的时候是一个数据帧一个数据帧进行发送的,最后一位第九位就是校验位
这种检验方式需要自己进一步的学习,后续会补充到
7.0 串口通信实验
注:复位串口的作用是将串口的状态恢复成初始值,方便后面对串口进行配置
在初始化串口之前,通常会先复位它以确保所有的设置都回到初始状态,然后进行新的配置。所以,正确的初始化序列通常会包括先复位串口,使能时钟,然后配置串口参数(如波特率、数据位数、停止位数等),最后可能还需要使能接收和发送功能。
直接按照上面的示例步骤进行配置即可,以下是程序的结构
USART.C文件代码
#include "gd32f30x.h" // Device header
#include <stdint.h>
#include <stdio.h>
/*
*****************************************
* @brief : 串口使用的资源信息
* @param : uartNo 哪一个串口,rcuUart 哪一个串口时钟,rcuGpio GPIO口时钟
* @param : gpio 口,txPin 对应的管脚,rxPin 对应的管脚
* @retval: 无返回值
*****************************************
*/
typedef struct
{
uint32_t uartNo;
rcu_periph_enum rcuUart;
rcu_periph_enum rcuGpio;
uint32_t gpio;
uint32_t txPin;
uint32_t rxPin;
}UartHwInfo_t;
static UartHwInfo_t g_usartHwInfo =
{
USART0,RCU_USART0,RCU_GPIOA,GPIOA,GPIO_PIN_9,GPIO_PIN_10
};
/*
*****************************************
* @brief : GPIO 初始化
* @param : 无参数
* @retval: 无返回值
*****************************************
*/
static void Gpio_Init(void)
{
rcu_periph_clock_enable(g_usartHwInfo.rcuGpio);
gpio_init(g_usartHwInfo.gpio,GPIO_MODE_AF_PP,GPIO_OSPEED_10MHZ,g_usartHwInfo.txPin);
gpio_init(g_usartHwInfo.gpio,GPIO_MODE_IPU,GPIO_OSPEED_10MHZ,g_usartHwInfo.rxPin);
}
/*
*****************************************
* @brief : USART 初始化
* @param : uint32_t baudRate 波特率
* @retval: 无返回值
*****************************************
*/
static void Usart_Init(uint32_t baudRate)
{
rcu_periph_clock_enable(g_usartHwInfo.rcuUart);
usart_deinit(g_usartHwInfo.uartNo);
usart_word_length_set(g_usartHwInfo.uartNo,USART_WL_8BIT);
// 设置校验位,表示没有校验
usart_parity_config(g_usartHwInfo.uartNo,USART_PM_NONE);
// 串口的停止位
usart_stop_bit_set(g_usartHwInfo.uartNo,USART_STB_1BIT);
// 串口波特率
usart_baudrate_set(g_usartHwInfo.uartNo,baudRate);
// 使能串口发送
usart_transmit_config(g_usartHwInfo.uartNo,USART_TRANSMIT_ENABLE);
// 使能串口
usart_enable(g_usartHwInfo.uartNo);
}
/*
*****************************************
* @brief : USART 发送测试函数
* @param : 无参数
* @param : 无参数
* @retval: 返回值无
*****************************************
*/
void USART_Send(void)
{
uint8_t i = 0;
for(i = 0; i < 255; i++)
{
usart_data_transmit(g_usartHwInfo.uartNo,i);
// 判断发送数据寄存器是否为空,空表示数据发送完毕
while(usart_flag_get(g_usartHwInfo.uartNo,USART_FLAG_TBE) == RESET);
}
// 判断TC是否设置为1
while(usart_flag_get(g_usartHwInfo.uartNo,USART_FLAG_TC) == RESET);
usart_transmit_config(g_usartHwInfo.uartNo,USART_TRANSMIT_DISABLE);
}
/*
*****************************************
* @brief : USART 初始化函数
* @param : 无参数
* @param : 无参数
* @retval: 返回值无
*****************************************
*/
void Usart_Tx_Init(void)
{
Usart_Init(115200);
Gpio_Init();
}
/*
*****************************************
* @brief : printf 函数默认打印输出到显示器,
如果要显示输出到串口,必须重新实现fput
将输出指向串口,称之为重定向
* @param : int ch
* @param : FILE* F
* @retval: ch
*****************************************
*/
int fputc(int ch, FILE* f)
{
// ch 是ASCII码需要强制类型转换
usart_data_transmit(g_usartHwInfo.uartNo,(uint8_t) ch);
while(usart_flag_get(g_usartHwInfo.uartNo,USART_FLAG_TBE) == RESET);
return ch;
}
USART.H文件代码
#ifndef __USART_H_
#define __USART_H_
void Usart_Tx_Init(void);
void USART_Send(void);
#endif
MAIN.C文件
#include <stdio.h>
#include "gd32f30x.h"
#include "Delay.h"
#include "LED.h"
#include "Key.h"
#include "USART.h"
#include <stdio.h>
int main(void)
{
// 初始化LED
LED_Init();
KeyDrvInit();
// 串口初始化接口函数
Usart_Tx_Init();
// 串口测试程序
// USART_Send();
printf("This is UART printf test!\r\n"); // 打印到显示器里面,并不是打印到串口
while(1){
}
}
8.0 程序发送数据运行结果
9.0 fpuchar函数重定向
使用这个函数默认是打印在显示器上的,要是想要这个数据在串口上打印输出需要对这个函数进行从定向fputc()函数。
/*
打印输出程序,pritf函数默认打印输出到显示器
如果需要输出到串口,必须重新实现fputc函数,
将输出指向串口,称之为重定向
*/
int fputc(int ch,FILE *f){
usart_data_transmit(g_uartHwInfo.uartNo, (uint8_t)ch);
while (RESET == usart_flag_get(g_uartHwInfo.uartNo, USART_FLAG_TBE));
return ch;
}
9.0 补充标志位参数知识
例如:
/* get flag USART0 state */
FlagStatus status;
status = usart_flag_get(USART0,USART_FLAG_TBE);
以上知识基于本人学习总结与理解,仅用于学习参考,参考郭天祥老师教学视频与文档撰写
。。。
作者:_沧浪之水_