STM32F103 使用寄存器方式配置和使用串口(USART)进行数据的发送和接收是一个相对底层且直接的操作。
以下是我例的一个简化的步骤,用于配置 STM32F103 的 USART进行基本的发送和接收操作:
1. 初始化 GPIOUSART2 通常使用 PA9 (TX) 和 PA10 (RX) 作为其引脚。你需要配置这两个引脚为复用推挽输出(对于 TX)和浮空输入(对于 RX)。2. 初始化 USART设置 USART 的波特率、数据位、停止位和校验位。使能 USART 的接收和发送中断(如果需要中断驱动)。使能 USART。3. 发送数据将数据写入 USART 的数据寄存器(USART->DR)。等待发送完成(可以通过查询标志位或中断来实现)。4. 接收数据读取 USART 的数据寄存器(USART->DR)来获取接收到的数据。清除相关的接收标志位。在中断服务例程中处理接收到的数据。这里只给出一些关键的代码片段,而不是完整的初始化函数或中断服务例程。
还是把原理图弄过来,方便分析:
主核心代码:
串口初始化:
串口参数波特率:串口通信的速率起始位:标志一个数据帧的开始,固定为低电平数据位:数据帧的有效载荷,1为高电平,0为低电平,低位先行校验位:用于数据验证,根据数据位计算得来停止位:用于数据帧间隔,固定为高电平还是把代码帖上来:
void My_USART1(void) { GPIO_InitTypeDef GPIO_InitStruct; USART_InitTypeDef USART1_InitStrue; NVIC_InitTypeDef NVIC_InitStructure; //1、串口时钟、GPIOA时钟使能 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1, ENABLE); //2、GPIOA端口模式设置 GPIO_InitStruct.GPIO_Pin = USART1_GPIO_PIN_TX;//PA9 GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStruct); GPIO_InitStruct.GPIO_Pin = USART1_GPIO_PIN_RX;//PA10 GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING; //GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStruct); //3、串口参数初始化 USART1_InitStrue.USART_BaudRate = 9600; USART1_InitStrue.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART1_InitStrue.USART_Mode = USART_Mode_Rx|USART_Mode_Tx; USART1_InitStrue.USART_Parity = USART_Parity_No; USART1_InitStrue.USART_StopBits=USART_StopBits_1; USART1_InitStrue.USART_WordLength = USART_WordLength_8b; USART_Init( USART1, &USART1_InitStrue); //4、开启中断并且初始化NVIC USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); NVIC_InitStructure.NVIC_IRQChannel =USART1_IRQn ; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; NVIC_InitStructure.NVIC_IRQChannelCmd= ENABLE; NVIC_Init(&NVIC_InitStructure); //5、使能串口 USART_Cmd(USART1,ENABLE); //6、编写中断处理函数 } void USART_SendByte(USART_TypeDef* USARTx, uint16_t Data) { /* Check the parameters */ assert_param(IS_USART_ALL_PERIPH(USARTx)); assert_param(IS_USART_DATA(Data)); /* Transmit Data */ USARTx->DR = (Data & (uint16_t)0x01FF); while (USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET); } void USART_SendString( USART_TypeDef * USARTx, char *str) { while(*str!='\0') { USART_SendByte( USARTx, *str++ ); } while(USART_GetFlagStatus(USARTx,USART_FLAG_TC)==RESET); } uint8_t USART_ReceiveByte(USART_TypeDef* USARTx) { while(USART_GetFlagStatus(USARTx,USART_FLAG_RXNE)==RESET); return (uint8_t)USART_ReceiveData(USART1); } void USART1_IRQHandler() { u16 temp; // while(USART_GetITStatus(USART1,USART_IT_RXNE) == RESET); if(USART_GetITStatus(USART1,USART_IT_RXNE) != RESET) { temp = USART_ReceiveData(USART1); } USART_SendByte(USART1,temp); } #pragma import(__use_no_semihosting) struct __FILE { int handle; }; FILE __stdout; _sys_exit(int x) { x = x; } int fputc(int ch, FILE *f) { USART_SendData(USART1, (uint8_t) ch); while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); return (ch); } int fgetc(FILE *f) { while (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET); return (int)USART_ReceiveData(USART1); } int main(void) { char i; LED_GPIO_Config(); delay_init(); //KEY_GPIO_Config(); //TIM2_Init(4999,7199); My_USART1(); USART_SendString(USART1, "电子产品世界"); while(1) { }; }
解释一下函数的意思:
My_USART1(void)这个函数用于初始化USART1。时钟使能:首先,它使能了USART1和GPIOA的时钟,因为USART1的TX和RX引脚通常连接到GPIOA。GPIO初始化:然后,它设置了GPIOA的引脚模式,将TX引脚设置为复用推挽输出,RX引脚设置为浮空输入。USART初始化:接着,它配置了USART1的参数,如波特率、硬件流控制、工作模式、校验位、停止位和数据位。中断和NVIC配置:它启用了USART1的接收中断,并配置了NVIC(嵌套向量中断控制器)以处理该中断。使能串口:最后,它使能了USART1。USART_SendByte(USART_TypeDef* USARTx, uint16_t Data)这个函数用于发送一个字节的数据。参数检查:它首先检查传入的USART指针和数据是否在有效范围内。发送数据:然后,它将数据写入USART的数据寄存器(DR)。等待发送完成:它使用循环等待,直到TXE(发送数据寄存器空)标志被设置,表示数据已被发送出去。USART_SendString(USART_TypeDef * USARTx, char *str)这个函数用于发送一个字符串。发送字符串:它遍历字符串,对每个字符调用USART_SendByte函数进行发送。等待传输完成:在所有字符发送后,它等待TC(传输完成)标志被设置,表示整个字符串已发送完成。USART_ReceiveByte(USART_TypeDef* USARTx)这个函数的目的是接收一个字节的数据,但你的代码片段中USART_ReceiveByte函数没有完整,我会假设其可能的实现。接收数据:它应该读取USART的数据寄存器(DR)来获取接收到的数据。清除中断标志:如果函数是为了中断驱动的接收而编写的,它还需要清除相应的中断标志。
实际工作状态:
发送接收回来的结果:
中文英文数字都可以收到:
总结:是重定义fputc函数,让他变成向上位机发送数据,发送的数据会通过串口调试助手打印出来。里面有接收函数,也发送,发送相关代码主要在函数里面实现。从这个串口代码中还是学到了如何使用串口的一些实用的功能,原来串口还可以这样用。