基于STM32F407ZGT6的USART串口发送和接收

通信方式

串/并行通信的概念和特点

  • 串行通信:逐位传输,数据位按顺序依次传输,传输速度较慢,成本相对较低,适用于远距离通信、成本敏感的应用场景,如电话线通信、USB接口等。。

  • 并行通信:多位同时传输,数据位同时发送和接收,传输速度更快,成本相对较高,适用于短距离、高速率的数据传输场景,如计算机内部总线、计算机内部的CPU与内存之间的数据传输,高速数据传输系统等。

  • 抗干扰能力

    • 串行通信由于采用单条数据线或差分线传输数据,因此抗干扰能力较强。

    • 并行通信由于存在多条传输线,容易受到信号干扰和串扰的影响,因此抗干扰能力相对较弱。

通信接口

通信的目的:将一个设备的数据传送到另一个设备,扩展硬件系统

(扩展STM32系统,与别的模块互联,实现外挂模块和读取外挂模块数据)

通信协议:制定通信的规则,通信双方按照协议规则进行数据收发

相关概念

全双工:通信双方能够同时进行双向通信,发送线路与接收线路互不影响(两根通信线)(打电话)

半双工:通信双方在同一时间只能进行单向通信(发电报)

单工:数据只能从一个设备到另一个设备,而不能反着来(收音机)

同步:有单独的时钟线(CLK),接收方可以在时钟信号的指引下进行采样

异步:没有始时钟线,需要双方约定一个采样频率,加入帧头帧尾进行采样位置的对齐(在数据库信号中穿插一些同步用的信号位,或者把主体数据进行打包,以数据帧的格式传输数据)

单端:引脚的高低电平都是对GND的电压差,所以必须要接GND

差分:靠两个差分引脚的电压差来传输信号的(使用差分信号可以极大地提高看干扰特性,所以一般差分信号的传输速度和距离都会非常高,性能也不错)

比特率(Bitrate) :每秒传输的比特数量,通常用比特每秒(bps)表示。一个比特表示每秒传输一个二进制位。 波特率(Baudrate):每秒传输的信号变化的次数,通常用波特(baud)表示。一个波特表示每秒传输一个信号变化(通常是电平变化)。

串口通信(使用串行通信)

基于TTL的UART通讯

Universal Asynchronous Receiver/Transmitter

通用*异步收发传输器 是一种串行通信协议 (全双工通信)

TTL电平:+3.3V或+5V表示1,0V表示0

UART是USART协议应用最简单的使用场景。即直接把数字I/O输出的高低电平作为实际的物理信号进行传输。单端需要共地

UART帧结构

波特率:串口通信的速率

空闲位:设备之间不传输数据时以持续的高电平表示空闲

起始位:标志一个数据帧的开始,固定为一个bit的低电平

数据位:数据帧的有效载荷,1为高电平,0为低电平,低位先行,8bits或9bits

一般地:9位字长选择有校验,8位字长选择无校验,这样每一帧的有效载荷都是1字节

校验位:用于数据验证,根据数据位计算得来

奇校验:1的个数必须为奇数个,不足最后一位补1,足就补0

偶校验:1的个数必须为偶数个,不足最后一位补1,足就补0

停止位:用于数据帧间隔,固定为高电平(1bit(大部分)、1.5bits或者2bits),恢复空闲

空闲状态引脚为高电平1,起始位为低电平产生下降沿

USART串口通讯

Universal Synchronous/Asynchronous Receiver/Transmitter

(通用同步/异步收发传输器)包含UART的所有特性

TX(Transmit)引脚:发送数据 RX(Receive)引脚:接收数据

USART1_TX - PA9,RX - PA10是APB2总线上的,

USART2_TX - PA2,RX - PA3和USART3_TX - PB10,RX - PB11是APB1总线上的

USART初始化结构体——USART_InitTypeDef:
typedef struct {
uint32_t USART_BaudRate; // 波特率
uint16_t USART_WordLength; // 数据帧字长(8 or 9)
uint16_t USART_StopBits; // 停止位
uint16_t USART_Parity; // 校验位
uint16_t USART_Mode; // USART 模式
uint16_t USART_HardwareFlowControl; // 硬件流控制
} USART_InitTypeDef;

1) USART_BaudRate:波特率设置。一般设置为2400、9600、19200、115200。标准库函数会根据 设定值计算得到USARTDIV 值,并设置USART_BRR 寄存器值。

2) USART_WordLength:数据帧字长,可选8 位或9 位。它设定USART_CR1 寄存器的M 位的值。 如果没有使能奇偶校验控制,一般使用8 数据位;如果使能了奇偶校验则一般设置为9 数据位。

3) USART_StopBits:停止位设置,可选0.5 个、1 个、1.5 个和2 个停止位,它设定USART_CR2 寄存器的STOP[1:0] 位的值,一般我们选择1 个停止位。

4) USART_Parity:奇偶校验控制选择,可选USART_Parity_No(无校验)、USART_Parity_Even(偶 校验) 以及USART_Parity_Odd(奇校验),它设定USART_CR1 寄存器的PCE 位和PS 位的值。

5) USART_Mode:USART 模式选择,有USART_Mode_Rx 和USART_Mode_Tx,允许使用逻辑或 运算选择两个,它设定USART_CR1 寄存器的RE 位和TE 位。

6) USART_HardwareFlowControl:硬件流控制选择,只有在硬件流控制模式才有效,可选有 使 能RTS、 使能CTS、同时使能RTS 和CTS、不使能硬件流。

串口的发送和接收代码

Ctrl+Alt+空格 联想代码

步骤

1.查看原理图确定串口引脚 USART1 USART1_TX PA9 USART1_RX PA10

2.GPIO配置 ... 选择复用模式 GPIO_InitStructure.GPIO_Mode= GPIO_Mode_AF; //复用模式

3.USART1配置 a.结构体申明

USART_InitTypeDef USART_InitStructure;

b.时钟使能 使能USART1的时钟

RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);

c.将GPIO引脚复用为串口 - 使用USTAR1串口

GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1); //TX 发送
GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1);//RX 接收

d.配置结构体 ​ 波特率、模式(收/发)、终止位、校验位、数据位、流控

USART_InitStructure.USART_BaudRate = 9600; //波特率
USART_InitStructure.USART_WordLength = USART_WordLength_8b;    //8位数据位
USART_InitStructure.USART_StopBits = USART_StopBits_1;        //1位停止位
USART_InitStructure.USART_Parity = USART_Parity_No; //无奇偶校验
USART_InitStructure.USART_Mode = USART_Mode_Rx|USART_Mode_Tx; //收和发都使能,进行或操作
USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;//无硬件流控

CTS清除发送 RTS请求发送

c.初始化

USART_Init(USART1, &USART_InitStructure);

串口中断(可选) - 接收可以使用查询和中断两种方式 和前面学习的中断一样

NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; //外部中断4 EXTI4
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x00;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);

使能接收中断

USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);

重写串口中断服务函数

uint16_t USART_RxData, 	USART_RxFlag;
uint8_t USART_GetRxFlag(void)
{
    if(USART_RxFlag == 1)
    {
        USART_RxFlag =0;
        return 1;
    }
    return 0;
}

uint8_t USART_GetRxData(void)
{
    return USART_RxData;
}

void USART1_IRQHandler(void)
{	
	//判断串口接收中断标志是否被置位
	if(USART_GetITStatus(USART1 ,USART_IT_RXNE) == SET)
	{
		USART_RxData = USART_ReceiveData(USART1);
		
		USART_RxFlag =1;
		
		//清楚中断标志
		USART_ClearITPendingBit(USART1 ,USART_FLAG_RXNE);
	}
}

4.使能串口

USART_Cmd(USART1, ENABLE);

5.使用串口

调用USART_SendData / USART_ReceiveData

6.串口重定向

添加stdio.h

//重定向fputc - 是printf的底层
int fputc(int ch, FILE *stream)
{
    USART_SendData(USART1 ,(uint16_t)ch);
    //等待数据发送寄存器为空
    //USART_FLAG_TXE 表示寄存器可以写入下一个数据了,当为SET的时候可以写入
    while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);

    return ch;
}

void usart_printf(char *format, ... )//可变参数
{
	char String[100];
	va_list arg;
	va_start(arg,format);
	vsprintf(String,format,arg);
	va_end(arg);
	usart_string(USART1,String);
}
//发单个字符
void usart_sendbyte(USART_TypeDef* usrUSARTx, uint16_t ch)
{
	USART_SendData(usrUSARTx,ch);
	
	//等待数据发送寄存器为空
	//USART_FLAG_TXE 表示寄存器可以写入下一个数据了,当为SET的时候可以写入
	while(USART_GetFlagStatus(usrUSARTx, USART_FLAG_TXE) == RESET);
	
}

//发字符串
void usart_string(USART_TypeDef* usrUSARTx, char *str)
{
	int i= 0;
	
	do
	{
		usart_sendbyte(usrUSARTx, *(str+i));
		i++;
	}	
	while(*(str+i) != '\0' );
}
//发送数组
void usart_sendarray(uint8_t *Array, uint16_t Length)
{
	uint16_t i;
	for(i = 0;i < Length; i++)
	{
		usart_sendbyte(USART1,Array[i]);
	}
}
//返回x的y次方
uint32_t usart_pow(uint32_t x,uint32_t y)
{
	uint32_t result = 1;
	while(y--)
	{
		result *= x;
	}
	return result;
}
//发送数字
void usart_sendnumber(uint32_t number,uint8_t length)
{
	uint8_t i;
	for(i=0;i<length;i++)
	{
		usart_sendbyte(USART1, number / usart_pow(10,length - i - 1) % 10 + '0');//从高位开始取 再加给偏移
	}
}

main.c

int main(void)
{
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	
	OLED_init();
	//串口的发送
	usart1_init();
	usart_sendbyte(USART1,'A');
	
	uint8_t Array[] = {0x42, 0x43, 0x44, 0x45};
	usart_sendarray(Array,4);
	
	usart_string(USART1,"HelloWordl!\r\n");//  \r\n进行换行
	
	usart_sendnumber(12345, 5);

	printf("NUM = %d\r\n",666);
	
	char String[100];
	sprintf(String,"NUM = %d\r\n",666);//每个串口都可以使用sprintf进行打印,不涉及重定向的方向
	usart_string(USART1,String);
	
	usart_printf("NUM = %d\r\n",666);
	
	//串口的接收 - 查询方式
	while(1)
	{
		if(USART_GetFlagStatus(USART1,USART_FLAG_RXNE) == SET)
		{
			RxData = USART_ReceiveData(USART1);//读完DR会自动清零标志位
			OLED_ShowHexNum(1,1RxData,2);
		}
	}
}

首先,你需要在STM32F407ZGT6上配置一个串口,然后使用相应的库函数来发送数据。下面是一个简单的示例代码: ```c #include "stm32f4xx.h" #include "stm32f4xx_usart.h" #include "stm32f4xx_gpio.h" #include "stm32f4xx_rcc.h" void USART_Config(void); int main(void) { USART_Config(); while(1) { // 发送数据 USART_SendData(USART1, 'A'); while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); } } void USART_Config(void) { GPIO_InitTypeDef GPIO_InitStruct; USART_InitTypeDef USART_InitStruct; NVIC_InitTypeDef NVIC_InitStruct; // 使能USART1和GPIOA的时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); // 配置PA9为复用功能,USART1_TX GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP; GPIO_Init(GPIOA, &GPIO_InitStruct); // 配置USART1 USART_InitStruct.USART_BaudRate = 115200; USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStruct.USART_Mode = USART_Mode_Tx; USART_InitStruct.USART_Parity = USART_Parity_No; USART_InitStruct.USART_StopBits = USART_StopBits_1; USART_InitStruct.USART_WordLength = USART_WordLength_8b; USART_Init(USART1, &USART_InitStruct); // 使能USART1 USART_Cmd(USART1, ENABLE); } ``` 在上面的代码中,我们使用USART1作为示例,使用PA9引脚作为USART1的TX引脚。在主函数中,我们使用`USART_SendData`函数来发送数据,同时使用`USART_GetFlagStatus`函数来检查发送寄存器是否为空,以确保数据已成功发送。在`USART_Config`函数中,我们首先使能USART1和GPIOA的时钟,然后配置PA9为复用功能,USART1_TX。接着,我们使用`USART_Init`函数来配置USART1的波特率、数据位、停止位等参数,最后使能USART1。 请注意,这只是一个简单的示例代码,实际的应用可能需要更多的配置和处理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值