最新在做LoRa的项目,使用的是STM32L072和SX1276,需要做一个串口透传模块,刚开始做demo的时候不考虑功耗,所以串口发送和接收直接使用下列函数执行 - HAL_UART_Transmit(&Sensor_UartHandle,(unsigned char *)&readcommand, sizeof(vcom_read_command_t), VCOM_START_DELAY);+ R. C f) ^) v* J( N
- HAL_UART_Receive(&Sensor_UartHandle,(unsigned char *)read_temp,UART_BUFFER_MAX_LEN, VCOM_RECV_TIMEOUT);
复制代码 都涉及到了超时时间,而超时时间依赖的是systick中断,接收发送100字节没问题。 但现在需要做低功耗,那么就不允许systick频繁中断了,于是考虑到串口中断接受,但stm32的库提供的函数让人看不明白: - HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
+ F* L- J* `7 j `: P - HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
复制代码 尝试一个晚上,现在收发没问题了,网上写的步骤不够详细,先将我的做法例举如下: 1.在串口初始化的时候打开串口中断,M0的芯片只有串口中断,不区分发送或者接收中断: - void CommandUartInit(void)
/ d9 I, P+ R7 N8 O9 z* n" t - {
5 Q% k& r# I6 y a& @. ]' U, V - Sensor_UartHandle.Instance = SENSOR_USARTX; 7 U, k7 S/ y* [9 `2 N& l
- Sensor_UartHandle.Init.BaudRate = 4800;
|. i; E9 ^ J% s% e7 Y8 Q3 a - Sensor_UartHandle.Init.WordLength = UART_WORDLENGTH_9B; /*8-bit data and 1-bit even bit*/" i2 g. ^! B, s! o9 a
- Sensor_UartHandle.Init.StopBits = UART_STOPBITS_1;
. k6 Q7 L) O: L% s% r - Sensor_UartHandle.Init.Parity = UART_PARITY_EVEN;/ T- O$ I; h1 P! n* b
- Sensor_UartHandle.Init.HwFlowCtl = UART_HWCONTROL_NONE;6 H6 e: _: `, S8 U* F# i
- Sensor_UartHandle.Init.Mode = UART_MODE_TX_RX;
2 H+ c0 d; k1 T, ]* r - if(HAL_UART_Init(&Sensor_UartHandle) != HAL_OK)
. ^4 `) z6 H9 U0 Q" Y - {
# O2 `% V0 k& {; N6 l" k( X+ w2 B* E - /* Initialization Error */
4 o, O K6 X+ s6 p - Error_Handler();
* a7 [ j( m0 r& W& b1 Q5 @ - }/ o! J2 _" I" @" Y- h9 U: q ]: x1 G
- ! M$ w1 C {5 g- p1 V8 V" @# u
- NVIC_EnableIRQ(USART2_IRQn);
1 f1 m# A9 o" r* `4 V9 e# a2 h q - NVIC_ClearPendingIRQ(USART2_IRQn);! H& g# Q" Q9 J
- }
复制代码 9 V7 M6 n' O9 T% @+ V6 m, |
2.添加中断处理函数,按照stm32文件惯例,中断函数在stm32xxx_it.c里面添加: - void USART2_IRQHandler(void)
4 z6 E' f/ `9 Y& r- h0 a/ \ - {
3 C/ |, X9 X9 m1 s- O8 x$ C, X, Y5 ] - HAL_UART_IRQHandler(&Sensor_UartHandle);5 e3 C3 g+ R& d; {( f) P
- }
复制代码这里需要说明的是,串口发送和接受的处理库已经帮我们做好了,全部封装在 void HAL_UART_IRQHandler(UART_HandleTypeDef *huart) 这个函数里,我们需要做的就是在中断处理函数里面调用这个函数而已,参数填写正确的串口号。 3. 在主循环中调用发送接收函数: - HAL_UART_Transmit_IT(&Sensor_UartHandle,(unsigned char *)&readcommand, sizeof(vcom_read_command_t));
1 [! ^6 n1 Y, b6 u$ y - do{3 w" r! C# W6 ~# |1 U
- uart_receive_status = HAL_UART_Receive_IT(&Sensor_UartHandle,(unsigned char *)read_temp,UART_BUFFER_MAX_LEN);
$ E$ N0 K1 g3 B3 D& B9 Z9 ^' ^0 s3 \ - temp_state=HAL_UART_GetState(&Sensor_UartHandle); 6 C* c$ v5 m* Q; N, d
- if(temp_state==HAL_UART_STATE_BUSY_RX || temp_state==HAL_UART_STATE_BUSY_TX_RX)
' |: f4 a- s$ A' z1 r - {, C- c7 X' h* L* X: W( {
- receive_timeout ++;
7 m, G9 g& L: R0 J) _* o" I" J/ ]% e - } 8 G* b ?8 ^' G" A s
- }while(Sensor_UartHandle.RxXferCount != 0 && receive_timeout < 10000);
复制代码 . D0 |" F( h0 L
这里有几点需要说明: 1)发送没什么好说的,直接调用HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)就可以将数据发送出去,可以发送任意size的数据。 2)接收函数做的比较恶心,HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size),每调用一次只接收一个字节,自己可以去分析static HAL_StatusTypeDef UART_Receive_IT(UART_HandleTypeDef *huart)。 3)说一下这几个函数之间的关系: 调用HAL_UART_Receive_IT()相当于开启接收中断--->如果有数据,会触发中断USART2_IRQHandler() ---> HAL_UART_IRQHandler() ---> UART_Receive_IT() 可以看到在HAL_UART_Receive_IT中设置的各种参数,在UART_Receive_IT中都会用到,uhdata = (uint16_t) READ_REG(huart->Instance->RDR);这个就是从串口数据寄存器中获取到的数据。 4)重新说明下,不管是发送数据还是接收数据都会触发中断,进而最终会调用到 UART_Receive_IT()这个函数,在这个函数里面分别对接收和发送做了处理,可以看看源码。 5)为了实现接受任意长度的数据,我定义了一个255字节的数组用于接受,然后加了一个超时时间,网上很多用系统时钟做超时,但我为了做低功耗,没有开启systick中断,所以就直接加了一个u32的变量去计数,超时时间要根据自己接收的最长数据调整。 6)很多人说在接收大数据的时候这个库函数有问题,项目太急,暂时就不研究了,等遇到的时候再研究吧。
! Q% p8 B& G7 y j/ a. D+ _) j6 [+ o |