本人工作之余自学,该博客是为了记录学习过程,以及一些心得。内容如有出错,欢迎大家纠正,谢谢。
单片机通讯
在嵌入式中,通信将主控芯片与传感器、存储芯片、外围控制芯片等连接了起来,使得功能不再受限于主控本身。
串行/并行通信
1、串行通信简单的说就是数据依次传输,比如要传输0x11111111,一位一位的发送,需要发送8次,串行传输占用的通信线更少,成本低,通信速度相对较慢。
2、并行通信则是几个数据一起传输,同样是0x11111111,如果8位一起发送,只需要发送1次并行传输占用的通信线多,成本高,通信速度相对更快。
3、随着对传输速度要求越来越高,并行传输开始出现信号之间的干扰,串行通信受干扰影响较小,之后又发展出差分传输等技术,极大的提高了串行传输速率,使得串行通信速度可能比并行通信速度更快。
全双工/半双工/单工传输
按照数据传输的方向,通信可以分为全双工、半双工和单工。全双工指双方都可以同时收发信息;半双工双方都可以收发信息,但同一时刻只能一方发送信息;单工指只能一方发信息,一方接受信息,通信是单向的。
同步/异步通信
按数据同步的方式,通信可以分为同步通信和异步通信。数据在双方之间传输时,需要制定规则保证数据传输的准确。
1、同步通信的做法是加一个时钟信号,发送方和接收方在这个时钟的节拍下传输数据,比如常见的SPI、I2C。
2、异步通信的做法是对数据进行封装,在数据开头加上起始信号,在数据结尾加上终止信号,双方就按这个规则传输数据。
因此,可以通过是否有时钟信号,初步判断是何种数据同步方式。
串口
假如微处理器和板载的蓝牙透传模块通信时,一般就使用TTL电平,引脚直接连接即可。假如微处理器在工业现场,需要连接一个几十米外的装置,则应该考虑将TTL电平转为RS232、RS422、RS485。RS232增加电压的方式来抗干扰,RS422和RS485使用差分方式传输,差分方式传输可以理解为,两个线是在一起的,它们受到的干扰几乎是一样的,那么它们的差值也是保持不变的,这样就可以避免干扰,传输更远的距离。
串口的硬件连接和时序
常见的用途
1、 连接串口接口的模块;比如WIFI模块,芯片的模块和WIFI模块至少需要三个引脚(发送、接收、接地),收发引脚交叉连接。
2、 作为调试口;打印程序运行的状态信息;
3、 通过电平转换芯片,变为RS232/RS485电平,用于复杂工业环境;
串口数据传输的格式:
1、确定波特率,即每秒传输多少个bit位;体现了传输速度的快慢。
2、起始位—首先在默认的情况下,引脚的电平是高电平,然后,发出一个逻辑0信号,表示数据的开始;
3、数据位—然后发送5~8位的逻辑0或逻辑1,先传输第0位再传输第一位,依次传输。即传输的数据。
4、校验位—来检验数据传输的准确性。(可选,可以选择不传输)
5、停止位—字符结束的标志。再次把引脚变为高电平。
在嵌入式中,很多MCU和外设模块都集成有UART外设。 STM32F103系列最多有3个通用同步异步收发器( Universal synchronous asynchronous receiver transmitter USART), 2个通用异步收发器( Universalasynchronous receiver transmitter, UART)。 USART和UART的主要区别在于, USART支持同步通信,该模式有一根时钟线提供时钟。
实例一:在STM32CubeMX上,配置串口,把串口1USART1,用做串口的打印调试。
1、 打开CubeMX工程,找到通讯Connectivity目录,选择USART1,模式选择异步模式,因为串口传输是没有时钟信号的。
2、 参数设置,默认波特率115200,数据长度是8bit位,没有奇偶校验,停止位是一位。(全部默认即可)
3生成工程
打开主函数MX_USART1_UART_Init()函数,定义了一个USART1的结构体,并初始化结构体。
UART_HandleTypeDef huart1;
UART_HandleTypeDef huart2;
/* USART1 init function */
void MX_USART1_UART_Init(void)
{
/* USER CODE BEGIN USART1_Init 0 */
/* USER CODE END USART1_Init 0 */
/* USER CODE BEGIN USART1_Init 1 */
/* USER CODE END USART1_Init 1 */
huart1.Instance = USART1;
huart1.Init.BaudRate = 115200;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
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();
}
/* USER CODE BEGIN USART1_Init 2 */
/* USER CODE END USART1_Init 2 */
}
在初始化串口之后,就可以使用HAL库提供的“ HAL_UART_Transmit()”从串口发送数据,使用“ HAL_UART_Receive()”接收数据,但这样使用不方便,需要自己处理数据类型。又因为这样发送的数据是原始数据,通常使用printf将数据格式化打印,比较方便。因此,这里需要重定向打印函数,在使用printf 时调用“ HAL_UART_Transmit()”打印。
重定向打印函数
1、HAL_UART_Transmit(&husart, (uint8_t*)&ch, 1, 10);函数参数修改为huart1;
2、添加头文件#include <stdio.h>;
点击魔法棒,打开工程选项界面,切换到“ Target”标签,勾选上“ Use MicroLIB”。
如果不勾选“ Use MicroLIB”,添加如下代码,可不在工程设置中勾选Use MicroLIB
/*
* 添加如下代码,可不在工程设置中勾选Use MicroLIB
*/
#pragma import(__use_no_semihosting)
struct __FILE
{
int a;
};
3、 返回主函数,主函数测试函数
printf("百问科技 www.100ask.net\n\r");
printf("UART 实验\n\r");
printf("test char = %c,%c\n\r", 'H', 'c');
printf("test string1 = %s\n\r", "www.100ask.net");
printf