完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
|
|
相关推荐
1个回答
|
|
相关寄存器
状态寄存器 (USART_SR) 主要关注RXNE位和TC位 RXNE(读数据寄存器非空):当该位被置1的时候,就是提示已经有数据被接收到了,并且可以读出来了。读取USART_DR,从而将该位清零,也可以向该位写0,直接清除。 TC(发送完成):当该位被置1的时候,表示USART_DR内的数据已经被发送完成了。如果设置了这个位的中断,则会产生中断。该位也有两种清零方式:读USART_SR,写USART_DR;直接向该位写0。 数据寄存器 (USART_DR) 进行发送数据操作时,往USART_DR写入数据会自动存储在TDR内;当进行读取数据操作时,向USART_DR读取数据会自动提取RDR数据。 发送数据时把TDR内容转移到发送移位寄存器上,接收数据时则是把接收到的每一位顺序保存在接收移位寄存器内进而转移到RDR。 波特率寄存器 (USART_BRR) 波特率寄存器包括定义了两个部分:DIV_Mantissa(整数部分)和DIV_Fraction(小数部分)。 控制寄存器 x (USART_CRx) 控制寄存器 1 (USART_CR1) 控制寄存器 2 (USART_CR2) 控制寄存器 3 (USART_CR3) 控制寄存器主要用于各类使能,如USART使能、检验控制使能、校验选择(奇校验偶校验)、发送缓冲区空中断使能、发送完成中断使能、接收缓冲区非空使能、发送使能、接受使能等等,具体位请查找中文参考手册。 串口配置 使用CubeMX配置. 串口初始化 UART_HandleTypeDef huart1; void MX_USART1_UART_Init(void) { huart1.Instance = USART1; huart1.Init.BaudRate = 115200; //波特率 huart1.Init.WordLength = UART_WORDLENGTH_8B; //字长为8位数据格式 huart1.Init.StopBits = UART_STOPBITS_1; //一个停止位 huart1.Init.Parity = UART_PARITY_NONE; //无奇偶校验位 huart1.Init.Mode = UART_MODE_TX_RX; //收发模式 huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE; huart1.Init.OverSampling = UART_OVERSAMPLING_16; if (HAL_UART_Init(&huart1) != HAL_OK) //初始化 { Error_Handler(); } HAL_UART_Receive_IT(&huart1, (uint8_t *)aRxBuffer, RXBUFFERSIZE); //该函数会开启接收中断:标志位UART_IT_RXNE,并且设置接收缓冲以及接收缓冲接收最大数据量,下文中断部分有介绍。 } 结构体类型UART_HandleTypeDef 变量huart1作为UART的句柄。如下图:其中UART_InitTypeDef用于初始化波特率,奇偶校验位等。 typedef struct __UART_HandleTypeDef { USART_TypeDef *Instance; /*!< UART registers base address */ UART_InitTypeDef Init; /*!< UART communication parameters */ uint8_t *pTxBuffPtr; /*!< Pointer to UART Tx transfer Buffer */ uint16_t TxXferSize; /*!< UART Tx Transfer size */ __IO uint16_t TxXferCount; /*!< UART Tx Transfer Counter */ uint8_t *pRxBuffPtr; /*!< Pointer to UART Rx transfer Buffer */ uint16_t RxXferSize; /*!< UART Rx Transfer size */ __IO uint16_t RxXferCount; /*!< UART Rx Transfer Counter */ DMA_HandleTypeDef *hdmatx; /*!< UART Tx DMA Handle parameters */ DMA_HandleTypeDef *hdmarx; /*!< UART Rx DMA Handle parameters */ HAL_LockTypeDef Lock; /*!< Locking object */ __IO HAL_UART_StateTypeDef gState; /*!< UART state information related to global Handle management and also related to Tx operations. This parameter can be a value of @ref HAL_UART_StateTypeDef */ __IO HAL_UART_StateTypeDef RxState; /*!< UART state information related to Rx operations. This parameter can be a value of @ref HAL_UART_StateTypeDef */ __IO uint32_t ErrorCode; /*!< UART Error code */ #if (USE_HAL_UART_REGISTER_CALLBACKS == 1) void (* TxHalfCpltCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Tx Half Complete Callback */ void (* TxCpltCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Tx Complete Callback */ void (* RxHalfCpltCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Rx Half Complete Callback */ void (* RxCpltCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Rx Complete Callback */ void (* ErrorCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Error Callback */ void (* AbortCpltCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Abort Complete Callback */ void (* AbortTransmitCpltCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Abort Transmit Complete Callback */ void (* AbortReceiveCpltCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Abort Receive Complete Callback */ void (* WakeupCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Wakeup Callback */ void (* MspInitCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Msp Init callback */ void (* MspDeInitCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Msp DeInit callback */ #endif /* USE_HAL_UART_REGISTER_CALLBACKS */ } UART_HandleTypeDef; GPIO配置,开启中断 void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle) { GPIO_InitTypeDef GPIO_InitStruct = {0}; if(uartHandle->Instance==USART1) { /* USART1 clock enable */ __HAL_RCC_USART1_CLK_ENABLE(); //使能串口1时钟 __HAL_RCC_GPIOA_CLK_ENABLE(); //使能GPIOA时钟 /* USART1 GPIO Configuration PA9 ------> USART1_TX PA10 ------> USART1_RX */ //GPIO配置 GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_10; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF7_USART1; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); /* USART1 interrupt Init */ //开启串口1中断 HAL_NVIC_SetPriority(USART1_IRQn, 0, 0); HAL_NVIC_EnableIRQ(USART1_IRQn); } } 中断函数 引用原子哥一张串口接收中断的流程图更好理解。 由流程图可以看到,当RxXferCount为0时,才调用中断回调函数 首先在.h文件中声明几个变量 #define USART_REC_LEN 200 //定义最大接收字节数 200 #define RXBUFFERSIZE 1 //缓存大小 extern uint8_t aRxBuffer[RXBUFFERSIZE]; //HAL库USART接收Buffer extern uint8_t USART_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符 extern uint16_t USART_RX_STA; //接收状态标记 我们在前文串口初始化时提到了HAL_UART_Receive_IT(&huart1, (uint8_t *)aRxBuffer, RXBUFFERSIZE);如下: HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size) { /* Check that a Rx process is not already ongoing */ if (huart->RxState == HAL_UART_STATE_READY) { if ((pData == NULL) || (Size == 0U)) { return HAL_ERROR; } /* Process Locked */ __HAL_LOCK(huart); huart->pRxBuffPtr = pData; huart->RxXferSize = Size; huart->RxXferCount = Size; huart->ErrorCode = HAL_UART_ERROR_NONE; huart->RxState = HAL_UART_STATE_BUSY_RX; /* Process Unlocked */ __HAL_UNLOCK(huart); /* Enable the UART Parity Error Interrupt */ __HAL_UART_ENABLE_IT(huart, UART_IT_PE); /* Enable the UART Error Interrupt: (Frame error, noise error, overrun error) */ __HAL_UART_ENABLE_IT(huart, UART_IT_ERR); /* Enable the UART Data Register not empty Interrupt */ __HAL_UART_ENABLE_IT(huart, UART_IT_RXNE); return HAL_OK; } else { return HAL_BUSY; } } 由函数定义可以看到,RxXferCount为我们传入的参数RXBUFFERSIZE为1,另外 这个函数使能了接收完成中断__HAL_UART_ENABLE_IT(huart, UART_IT_RXNE);,也就是说每接收一个字节就会进入一次中断USART1_IRQHandler。 串口1中断服务函数 串口产生中断,就会自动调用USART1_IRQHandler这个中断服务函数 void USART1_IRQHandler(void) { uint32_t timeout=0; uint32_t maxDelay=0x1FFFF; #if SYSTEM_SUPPORT_OS //使用OS OSIntEnter(); #endif HAL_UART_IRQHandler(&huart1); //调用HAL库中断处理函数 timeout=0; while (HAL_UART_GetState(&huart1)!=HAL_UART_STATE_READY)//等待就绪 { timeout++;超时处理 if(timeout>maxDelay) break; } timeout=0; while(HAL_UART_Receive_IT(&huart1,(uint8_t *)aRxBuffer, RXBUFFERSIZE)!=HAL_OK)//一次处理完成之后,重新开启中断并设置RxXferCount为1 { timeout++; //超时处理 if(timeout>maxDelay) break; } #if SYSTEM_SUPPORT_OS //使用OS OSIntExit(); #endif } 在这个函数里,首先调用HAL_UART_IRQHandler(&huart1);这个HAL库中断处理函数,主要用于判断中断类型。通过这个中断处理函数会调用UART_Receive_IT(huart);如下:(由于函数太长,只选取了一小部分) void HAL_UART_IRQHandler(UART_HandleTypeDef *huart) { if (((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET)) { UART_Receive_IT(huart); } } 该函数是将接收到的数据保存到指定的串口缓冲区aRxBuffer。接着再判断。RxXferCount自减后是否等于0. 如果等于0 ,则关闭接收完成中断,进行中断回调函数。如果需要再一次开启时。需要再一次开启中断,也就是调用 HAL_UART_Receive_IT()函数。 串口1中断回调函数 首先,在win系统下enter表示回车(r)加换行(n),在16进制的表示下,r的ascii码为0x0d,n的ascii码为0x0a.由此下面逻辑就比较好理解了。16位置1表示接收完成,即0x8000;15位置1表示接收到了0x0d.将收到的数据储存在数组USART_RX_BUF[]里 void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if(huart->Instance==USART1)//如果是串口1 { if((USART_RX_STA&0x8000)==0)//接收未完成 { if(USART_RX_STA&0x4000)//接收到了0x0d r { if(aRxBuffer[0]!=0x0a) USART_RX_STA=0;//接收错误,重新开始 0x0a n else USART_RX_STA|=0x8000; //接收完成了 } else //还没收到0X0D { if(aRxBuffer[0]==0x0d) USART_RX_STA|=0x4000; else { USART_RX_BUF[USART_RX_STA&0X3FFF]=aRxBuffer[0] ; USART_RX_STA++; if(USART_RX_STA>(USART_REC_LEN-1)) USART_RX_STA=0;//接收数据错误,重新开始接收 } } } } } |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1800 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1629 浏览 1 评论
1096 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
735 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1684 浏览 2 评论
1944浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
744浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
578浏览 3评论
601浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
563浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-27 00:12 , Processed in 0.803970 second(s), Total 78, Slave 62 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号