阅读量:0
技术笔记!
1、数据通信的基本概念(了解)
2、串口(RS-232)(熟悉)
3、USART(通用同步异步接发器)
3.5 设置波特率
波特率计算公式:baud="fck" /(16∗USARTDIV);
"其中fck"是串口的时钟,如:USART1的时钟是PCLK2,其他串口都是PCLK1
波特比率寄存器(BRR):把USARTDIV的整数部分写入位[15:4], USARTDIV的小数部分写入[3:0]
如何使用寄存器操作的方式设置波特率?
波特率设置通用公式推演
3.6 USART寄存器
1. 控制寄存器1(CR1)
该寄存器需要完成的配置:
位13:使能USART
位12:配置8个数据位
位10:禁止检验控制
位5:使能接收缓冲区非空中断
位3:使能发送
位2:使能接收
2. 控制寄存器2(CR2)
该寄存器只需要完成的停止位的配置。
3. 控制寄存器3(CR3)
该寄存器配置是否需要选择半双工模式。
4. 数据寄存器(DR)
设置好控制和波特率寄存器后,往该寄存器写入数据即可发送,接收数据则读该寄存器。
5. 状态寄存器(SR)
3.7 需要配置的时序总结
4. HAL库外设初始化MSP回调机制(了解)
eg:
5. HAL库中断回调机制(了解)
eg:
6. USART/UART异步通信配置步骤(掌握)
7. HAL库相关函数
8. IO引脚复用功能(掌握)
9. 加入以下代码可使用printf函数进行输出
/* 加入以下代码, 支持printf函数, 而不需要选择use MicroLIB */ #if 1 #if (__ARMCC_VERSION >= 6010050) /* 使用AC6编译器时 */ __asm(".global __use_no_semihosting\n\t"); /* 声明不使用半主机模式 */ __asm(".global __ARM_use_no_argv \n\t"); /* AC6下需要声明main函数为无参数格式,否则部分例程可能出现半主机模式 */ #else /* 使用AC5编译器时, 要在这里定义__FILE 和 不使用半主机模式 */ #pragma import(__use_no_semihosting) struct __FILE { int handle; /* Whatever you require here. If the only file you are using is */ /* standard output using printf() for debugging, no file handling */ /* is required. */ }; #endif /* 不使用半主机模式,至少需要重定义_ttywrch\_sys_exit\_sys_command_string函数,以同时兼容AC6和AC5模式 */ int _ttywrch(int ch) { ch = ch; return ch; } /* 定义_sys_exit()以避免使用半主机模式 */ void _sys_exit(int x) { x = x; } char *_sys_command_string(char *cmd, int len) { return NULL; } /* FILE 在 stdio.h里面定义. */ FILE __stdout; /* MDK下需要重定义fputc函数, printf函数最终会通过调用fputc输出字符串到串口 */ int fputc(int ch, FILE *f) { while ((USART1->SR & 0X40) == 0); /* 等待上一个字符发送完成 */ USART1->DR = (uint8_t)ch; /* 将要发送的字符 ch 写入到DR寄存器 */ return ch; } #endif
10. 串口实验
usart.c
uint8_t g_rx_buffer[1]; /* HAL库使用的串口接收数据缓冲区 */ uint8_t g_usart1_rx_flag = 0; /* 串口接收到数据标志 */ UART_HandleTypeDef g_uart1_handle; /* UART句柄 */ /* 串口1初始化函数 */ /*PA10 RX PA9 TX*/ void usart_init(uint32_t baudrate) { g_uart1_handle.Instance = USART1; g_uart1_handle.Init.BaudRate = baudrate; g_uart1_handle.Init.WordLength = UART_WORDLENGTH_8B; g_uart1_handle.Init.StopBits = UART_STOPBITS_1; g_uart1_handle.Init.Parity = UART_PARITY_NONE; g_uart1_handle.Init.HwFlowCtl = UART_HWCONTROL_NONE; //硬件控制流 g_uart1_handle.Init.Mode = UART_MODE_TX_RX; HAL_UART_Init(&g_uart1_handle); HAL_UART_Receive_IT(&g_uart1_handle, (uint8_t*)g_rx_buffer, 1); } /* 串口MSP回调函数 */ void HAL_UART_MspInit(UART_HandleTypeDef *huart) { GPIO_InitTypeDef gpio_init_struct; if(huart->Instance == USART1) /* 如果是串口1,进行串口1 MSP初始化 */ { __HAL_RCC_USART1_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); gpio_init_struct.Pin = GPIO_PIN_9; gpio_init_struct.Mode = GPIO_MODE_AF_PP; /* 推挽式复用输出 */ gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH; /* 高速 */ HAL_GPIO_Init(GPIOA, &gpio_init_struct); /* 初始化串口1的TX引脚 */ gpio_init_struct.Pin = GPIO_PIN_10; gpio_init_struct.Mode = GPIO_MODE_AF_INPUT; /* 输入 */ gpio_init_struct.Pull = GPIO_PULLUP; /* 上拉 */ HAL_GPIO_Init(GPIOA, &gpio_init_struct); /* 初始化串口1的RX引脚 */ HAL_NVIC_SetPriority(USART1_IRQn, 3, 3); HAL_NVIC_EnableIRQ(USART1_IRQn); } } /* 串口1中断服务函数 */ void USART1_IRQHandler(void) { HAL_UART_IRQHandler(&g_uart1_handle); HAL_UART_Receive_IT(&g_uart1_handle, (uint8_t*)g_rx_buffer, 1); } /* 串口数据接收完成回调函数 */ void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if(huart->Instance == USART1) { g_usart1_rx_flag = 1; } }
main.c
int main(void) { HAL_Init(); /* 初始化HAL库 */ sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟,72M */ delay_init(72); /* 初始化延时函数 */ led_init(); /* 初始化LED */ usart_init(115200); /* 波特率设为115200 */ printf("请输入一个英文字符:\r\n\r\n"); while(1) { if(g_usart1_rx_flag == 1) { printf("您输入的字符为:\r\n"); HAL_UART_Transmit(&g_uart1_handle, (uint8_t*)g_rx_buffer, 1, 1000); while(__HAL_UART_GET_FLAG(&g_uart1_handle, UART_FLAG_TC) != 1); printf("\r\n"); g_usart1_rx_flag = 0; } else { delay_ms(10); } } }
本次实验为了熟悉串口usart的使用,通过配置usart的参数调用usart初始化函数实现初始化usart句柄,HAL_UART_Receive_IT函数实现接收中断,再通过MSP回调函数初始化GPIO、NVIC、CLOCK,最后重定义中断函数以及中断回调函数,在中断回调函数中得判断基地址是否是对应的基地址,如if(huart->Instance == USART1)。
主函数进行相关初始化,使用HAL_UART_Transmit发送接收到的字符,并且使用了__HAL_UART_GET_FLAG宏函数获取发送是否完成的标志。