理论:
串口采取异步通信,即不依赖时钟节拍来接收或发送数据,而是采用互相约定的波特率传输数据。
波特率与单位时间传输的比特数有关,波特率越大传输的数据越多
传输一个比特花费的时间T = 1 / 比特率
接受和发送数据的时候需要接受端和发送端:
UART传输数据是一位一位的向接收端传输,为了知道何时传输,又或者为了保证传输数据的完整正确性,规定了传输协议:
分别为开始、数据、校验、停止,其中校验位可要可不要
传输样例:
停止位取二进制数0,数据位一般有8位刚好能装下一个字符,一般的停止位是1位取值为1,校验一般不要
开发板原理图:
可以出开发板有两组收发引脚,但其实真正有效的只有一组即PA2和PA3,下面详细说一下:
上述是开发板中控制下载调试器部分的芯片,其一般作用就是将程序或固件加载到微处理器或微控制器,朴素的讲调试器主要作用就是将电脑代码导入到开发板的芯片中
也就是说下载调试器能连接电脑,STM32L071
要想能与电脑上的串口小助手通信,那就必须TX,RX能与电脑相连,所以下载调试器中的芯片GD32F350C8T6
上的PA9、PA10就必须先发送或者接收STM32L071
传来的数据,其真正的作用是一个连接作用,即将STM32L071
与电脑间接相连
而STM32L071的另外一组引脚没有与下载调试器相连所以也就没有作用
STM32L071
的TX,RX与GD32F350C8T6
引脚连接的部分:
而SET由开发板SELECT按键控制其高低电平,高低电平能使其接通1、4引脚或3、4引脚
CubMX配置:
Asynchronous: 异步通信
Keil配置:
Function.c和Function.h文件:
#include "Function.h"
#include "i2c.h"
#include "oled.h"
#include "usart.h"void OLED_Write(unsigned char type, unsigned char data){ // 写函数unsigned char Write_data[2];Write_data[0] = type;Write_data[1] = data;HAL_I2C_Master_Transmit(&hi2c3, 0x78, Write_data, 2, 0xff);
}void Function_OledEnable(unsigned char ms){ // Oled使能HAL_GPIO_WritePin(OLED_POWER_GPIO_Port, OLED_POWER_Pin, GPIO_PIN_RESET);HAL_Delay(ms);OLED_Init();
}void Function_SendInfromation(const char * data, uint16_t len){ // 发送信息HAL_UART_Transmit(&huart2, data, len, 0xff);
}void Function_ReceiveInfromation(char * data, uint16_t len){ // 接受信息HAL_UART_Receive(&huart2, data, len, 0xff);
}
#ifndef __FUNCTION__
#define __FUNCTION__
#include <stdint.h>void OLED_Write(unsigned char type, unsigned char data);
void Function_OledEnable(unsigned char ms);
void Function_ReceiveInfromation(char * data, uint16_t len);
void Function_SendInfromation(const char * data, uint16_t len);
#endif
main.c
#include "main.h"
#include "i2c.h"
#include "usart.h"
#include "gpio.h"
#include "Function.h"
#include "oled.h"
#include <string.h>
void SystemClock_Config(void);int main(void)
{char a[] = {4, 5, 6};char flag = 1;char b[] = {0, 0, 0};HAL_Init();SystemClock_Config();MX_GPIO_Init();MX_I2C3_Init();MX_USART2_UART_Init();Function_OledEnable(50);while (1){OLED_ShowString(0, 0, "i am wining", 16);if(flag <= 2){flag ++;HAL_Delay(5000);Function_SendInfromation(a, strlen(a));HAL_Delay(5000);}OLED_ShowString(0, 2, "Receive:", 16);Function_ReceiveInfromation(b, 3);if(b[0] == '@'){OLED_ShowString(64, 2, b, 16);b[0] = '1'; }}
}void SystemClock_Config(void)
{RCC_OscInitTypeDef RCC_OscInitStruct = {0};RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};/** Configure the main internal regulator output voltage*/__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);/** Initializes the RCC Oscillators according to the specified parameters* in the RCC_OscInitTypeDef structure.*/RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;RCC_OscInitStruct.HSIState = RCC_HSI_ON;RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;RCC_OscInitStruct.PLL.PLLMUL = RCC_PLLMUL_4;RCC_OscInitStruct.PLL.PLLDIV = RCC_PLLDIV_2;if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK){Error_Handler();}/** Initializes the CPU, AHB and APB buses clocks*/RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK){Error_Handler();}PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART2|RCC_PERIPHCLK_I2C3;PeriphClkInit.Usart2ClockSelection = RCC_USART2CLKSOURCE_PCLK1;PeriphClkInit.I2c3ClockSelection = RCC_I2C3CLKSOURCE_PCLK1;if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK){Error_Handler();}
}/* USER CODE BEGIN 4 *//* USER CODE END 4 *//*** @brief This function is executed in case of error occurrence.* @retval None*/
void Error_Handler(void)
{/* USER CODE BEGIN Error_Handler_Debug *//* User can add his own implementation to report the HAL error return state */__disable_irq();while (1){}/* USER CODE END Error_Handler_Debug */
}#ifdef USE_FULL_ASSERT
/*** @brief Reports the name of the source file and the source line number* where the assert_param error has occurred.* @param file: pointer to the source file name* @param line: assert_param error line source number* @retval None*/
void assert_failed(uint8_t *file, uint32_t line)
{/* USER CODE BEGIN 6 *//* User can add his own implementation to report the file name and line number,ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) *//* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
效果:
程序启动后等10s钟后发送数据:
拓展:
HAL_UART_Transmit
与HAL_UART_Receive
,在传输与接收数据的时候,都会对做一些检查,例如指针数据长度是否有效,收发是否有效,如果不合格就会返回错误,如果合格就会进入忙碌状态即利用while函数一直对数据进行转发,或者收取。
在接受数据的时候,如果未能及时接收,那么后到的数据回应超时未接收报错,然后终止操作,这就是为什么在主函数有程序抢占cpu时不能即时接收数据,最后显示的数据只有一个字符。
这种情况可以用中断串口通信解决。