完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
|
|
相关推荐
1个回答
|
|
前言 Q: 为什么写这篇文章? 笔者其实也是小白,看了一些书籍和网上的教程,发现有一个比较严重的问题——网络及书籍的方法不够简 明,导致笔者学习时废了很大力气。网络及书籍的方法大多着重在数据的接收校验上,导致教程难以理解,其实芯片并没有想象的这么不稳定,对于稳定性要求不高的设计,接收时可以睁一只眼闭一只眼,只考虑最简单的方法是最有利于初学者入门的。 本人使用的芯片: STM32F103RCT6 正文 定义一个void USARTINIT(void)函数用于初始化 在使用USART1串口通信时,首先肯定要初始化,初始化函数内,可以分为以下几个步骤: 1.定义用于初始化的结构体变量: GPIO_InitTypeDef PIN; //RX:PA10, TX:PA9 NVIC_InitTypeDef NV; //NV用于初始化中断 USART_InitTypeDef US; //US为串口配置 2.使能外设 RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1, ENABLE ); USART_DeInit( USART1 ); //重置串口1 3.RX和TX的gpio配置: PIN.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽 PIN.GPIO_Pin = GPIO_Pin_9; //PA9对应TX PIN.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init( GPIOA, &PIN ); PIN.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮动输入 PIN.GPIO_Pin = GPIO_Pin_10; PIN.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init( GPIOA, &PIN ); 4.NVIC配置: NVIC_PriorityGroupConfig( NVIC_PriorityGroup_1 ); NV.NVIC_IRQChannel = USART1_IRQn;//打开串口中断 NV.NVIC_IRQChannelPreemptionPriority = 1;//数值在规定范围内可以随意,因为就只有这个中断 NV.NVIC_IRQChannelSubPriority = 1; NV.NVIC_IRQChannelCmd = ENABLE;//使能中断 NVIC_Init( &NV ); 5.USART配置: 笔者推荐的波特率为4800或9600,出问题可以尝试1200或2400 US.USART_BaudRate = BOUND; //BOUND可以自己#define一个值,如果读出的数有问题,可以尝试调低 US.USART_Parity = USART_Parity_No; //校验位为无 US.USART_StopBits = USART_StopBits_1;//停止位为1 US.USART_WordLength = USART_WordLength_8b;//字长为8位 US.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//关硬件流操作 US.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//设置串口模式,RX和TX都设置 USART_Init( USART1, &US );//串口初始化 USART_Cmd( USART1, ENABLE );//串口使能,这个很重要!很多教程都没有 现在不得不讲一下比较常用的寄存器,在串口中,有两个和数据收发有直接联系的寄存器:DR(数据寄存器)和SR(状态寄存器);DR既存放接收的数据也可以发送数据,SR寄存器存放的是DR寄存器的状态 如下图: 从上图可以看到几个SR寄存器常用的位:TC位、RXNE位。TC位在程序中用于判断发送操作是否完成;而RXNE位用于判断数据接收是否完成。 这样一来,我们就可以理清串口数据收发的思路了: 1.首先读出RS寄存器的TC位或RXNE位,判断收发是否完成。 2.将数据接收或发送。 在STM32中,我们可以使用库函数,来获取TC和RXNE的值 USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG); //获得SR某一位的值 所以,在上文的初始化后,可以调用函数USART_SendData或直接给DR寄存器赋值对串口发送数据 USART_SendData( USART1, 'H' ); //发送字符‘H’ 或 USART1 -> DR = 0x48; 但是在发送前,我们还需要读状态,所以 while( USART_GetFlagStatus( USART1, USART_FLAG_TC ) == 0 );//如果TC位为0则等待 USARTx -> DR = dat; //上面确认可以传输数据后发送dat数据 同样的,读之前也要读RXNE位,于是读操作为 unsigned char res = 0;//存放数据 while(1){ //如果RXNE等于1,代表接收完成,则接收数据给res并发送回串口 if( USART_GetFlagStatus( USART1, USART_FLAG_RXNE ) != 0 ){ res = USART1 -> DR; //res = USART_ReceiveData( USART1 ); while( USART_GetFlagStatus( USART1, USART_FLAG_TC ) == 0 ); USART1 -> DR = res; //USART_SendData( USART1, res ); } } 例程 下载例程:https://github.com/TTowFive/USART main.c #include "stm32f10x_conf.h" #include "UART.h" int main(){ uint8_t res; //接收到的数据 USARTNV(); USART_SEND_DATA( USART1, "你好!" ); while(1){ if( USART_GetFlagStatus( USART1, USART_FLAG_RXNE ) != 0 ){ res = USART1 -> DR; while( USART_GetFlagStatus( USART1, USART_FLAG_TC ) == 0 ); USART1 -> DR = res; } } } UART.h #ifndef UART_H #define UART_H #include "stm32f10x_conf.h" #define BOUND 9600 void USARTNV(void); void USART_SEND_DATA( USART_TypeDef* USARTx, uint8_t * dat ); #endif UART.c #include "UART.h" void USARTNV(){ GPIO_InitTypeDef PIN; NVIC_InitTypeDef NV; USART_InitTypeDef US; RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1, ENABLE ); USART_DeInit( USART1 ); PIN.GPIO_Mode = GPIO_Mode_AF_PP; PIN.GPIO_Pin = GPIO_Pin_9; PIN.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init( GPIOA, &PIN ); PIN.GPIO_Mode = GPIO_Mode_IN_FLOATING; PIN.GPIO_Pin = GPIO_Pin_10; PIN.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init( GPIOA, &PIN ); NVIC_PriorityGroupConfig( NVIC_PriorityGroup_1 ); NV.NVIC_IRQChannel = USART1_IRQn; NV.NVIC_IRQChannelPreemptionPriority = 1; NV.NVIC_IRQChannelSubPriority = 1; NV.NVIC_IRQChannelCmd = ENABLE; NVIC_Init( &NV ); US.USART_BaudRate = BOUND; US.USART_Parity = USART_Parity_No; US.USART_StopBits = USART_StopBits_1; US.USART_WordLength = USART_WordLength_8b; US.USART_HardwareFlowControl = USART_HardwareFlowControl_None; US.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; USART_Init( USART1, &US ); USART_Cmd( USART1, ENABLE ); } void USART_SEND_DATA( USART_TypeDef* USARTx, uint8_t * dat ){ while( *dat != ' |