一、串口
1.串口定义,将串口相关寄存器的首地址强制转化为串口结构体,方便通过结果体访问串口的寄存器
#define __IO volatile /*!< Defines 'read / write' permissions */
typedef struct
{__IO uint32_t SR; /*!< USART Status register, Address offset: 0x00 */__IO uint32_t DR; /*!< USART Data register, Address offset: 0x04 */__IO uint32_t BRR; /*!< USART Baud rate register, Address offset: 0x08 */__IO uint32_t CR1; /*!< USART Control register 1, Address offset: 0x0C */__IO uint32_t CR2; /*!< USART Control register 2, Address offset: 0x10 */__IO uint32_t CR3; /*!< USART Control register 3, Address offset: 0x14 */__IO uint32_t GTPR; /*!< USART Guard time and prescaler register, Address offset: 0x18 */
} USART_TypeDef;#define PERIPH_BASE 0x40000000UL /*!< Peripheral base address in the alias region */
#define APB1PERIPH_BASE PERIPH_BASE
#define USART3_BASE (APB1PERIPH_BASE + 0x00004800UL)
#define USART3 ((USART_TypeDef *)USART3_BASE)
2.若有奇偶校验位 16比特数据传输
/* In case of 9bits/No Parity transfer, pTxData needs to be handled as a uint16_t pointer */
if ((husart->Init.WordLength == USART_WORDLENGTH_9B) && (husart->Init.Parity == USART_PARITY_NONE))
{ptxdata8bits = NULL;ptxdata16bits = (const uint16_t *) pTxData;
}
else
{ptxdata8bits = pTxData;ptxdata16bits = NULL;
}
3.采样频率是波特率的16倍,起始位将采样位置定位到一位的中间
4.串口有一个字节的缓冲
现象:
串口助手连续发送received@abc
打印数据为:
9 received@
10 areceived@
10 areceived@
10 areceived@
10 areceived@
解释:
从框图得知(只看接收部分结构):
数据先进入接收移位寄存器,再进入接受数据寄存器
串口助手第一次发送received@abc,程序读取到@停止,即读到received@后停止,但是a进入串口接收移位寄存器,等接收数据寄存器读空,接收移位寄存器数据将移入接收数据寄存器,因此第二次读取数据时,从接收数据寄存器读取到的是字符’a’,后续读取received@,也就是说,第二次开始,读取的是areceived@。
while (1){rec_len = get_usart_line(rx_buf, rx_max_size, 500000);rx_buf[rec_len] = '\0';if(rec_len > 0) {char str[100];rec_len = snprintf(str, sizeof(str) / sizeof(str[0]), "%d %s\r\n", rec_len, rx_buf);HAL_UART_Transmit_DMA(&huart6, (uint8_t *)str, rec_len);// HAL_UART_Transmit_DMA(&huart6, rx_buf, rec_len);len = rec_len;}rx_buf[0] = 0;/* USER CODE END WHILE *//* USER CODE BEGIN 3 */}int get_usart_line(uint8_t *rx, int rx_max_size, int timeout) {int t = 0, i;uint8_t rx_buf = 0;for(i = 0; rx_buf != '@' && t < timeout && i < rx_max_size; t++) {if(HAL_UART_Receive(&huart6, &rx_buf, 1, 0) == HAL_OK) {// if(HAL_UART_Receive_DMA(&huart6, &rx_buf, 1) == HAL_OK) {rx[i++] = rx_buf;}}return t >= timeout ? -1 : i;
}
二、定时器
1.允许定时器中断
HAL_TIM_Base_Start_IT(&htim2);
2.重写定时器回调函数
函数原型:
/*** @brief Period elapsed callback in non-blocking mode* @param htim TIM handle* @retval None*/
__weak void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{/* Prevent unused argument(s) compilation warning */UNUSED(htim);/* NOTE : This function should not be modified, when the callback is needed,the HAL_TIM_PeriodElapsedCallback could be implemented in the user file*/
}
重写:
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{if(htim->Instance == TIM2) {static int cnt = 0;if(cnt < 500) led_on();else if(cnt < 1000) led_off();else cnt = 0;cnt++;}
}
三、DMA
1.触发方式
硬件触发:UART、ADC、IIC等外设设备
软件触发:M2M置1,内部触发,尽快连续触发传输计数器,快速转运数据,不能喝自动重装一起使用,否则会无限转运。
2.开关控制
当没有开启自动重装,计数器清零时需要先关闭DMA,重新填充初值,再开启DMA,注意必须先关闭
3.DMA通道
每个通道连接的外设不同,必须选择对应外设的通道才能转运,例如STM32F427IIH DMA+UART6 RX必须选择DMA2通道1或通道2 TX必须选择通道DMA2的通道6或7。