USART是一个全双工通用同步/异步串行收发模块,该接口是一个高度灵活的串行通信设备,相互独立的接收数据和发送数据;任何USART双向通信至少需要两个脚:接收数据输入(RX)和发送数据输出(TX)。为什么三种通讯方式一起学习呢?因为单片机最后都是要用到UASRT这个功能与外界通讯的。由于UART规定只是规定了数据(信号的时序)的格式,并没有规定接口的电气特性,这样导致了他们在物理层无法实现互联。
UART通讯时一般直接用处理器自己的TTL电平,(高电平表示1,低电平代表0)STM32自己的TTL电平是3.3V 51单片机的TTL电平是5V的 所以不能互连。RS232电平规定:逻辑“1”的电平是-5V~ -15V之间,逻辑“0”的电平是+5v~+15V之间,这么高的电压当然需要芯片转换后才能通讯了。232通讯程序和UART通讯程序都是一样的。
STM32F103LQFP48集成有3个UASRT控制器:编号及引脚定义如下:
名称 | 引脚 |
USART1 | PA9(30脚_TX) PA10(31脚_RX)可复用给42 43脚 |
USART2 | PA1(11脚_RTS) PA2(12脚_TX) |
USART3 | PA1(21脚_TX) PA2(22脚_RX) |
数据线端口是高电平状态①(红色线表示),如果开始发送数据了,那么总线将高电平拉低成低电平,然后开始发送数据,发送数据的顺序是先发数据的低位,然后发送到高位。一般是8位数据位(也可以是7位),然后是校验位(校验位可有可无),最后一位是停止位(停止位是必须有的)停止位可以是1位,1.5位,2位。
发送方这样不停的发送数据,接收方怎么知道发送的的0还是1呢?如果要发送0x00,和0xFF数据,这样总线是不是一直在高电平或者低电平,我们约定一个节拍(如:波特率9600指的是每秒可以传输9600个二进制位,传送一个位需要1/9600秒)双方共同遵守,这个节拍持续的时间长短,来换算成发送了多少个0或者多少个1了。尽管设置了相同的波特率,设备双方的时钟基准可能不太一样,为了防止累计误差出现,每次发完一个字节后又重新开始发送下一个字节,时间重新开始计时。
控制器内部结构图如下
初始化端口库函数
void USART1_Init(u32 bound){ //串口1初始化并启动
//GPIO端口设置
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE); //使能USART1,GPIOA时钟
//USART1_TX PA.9
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_Init(GPIOA, &GPIO_InitStructure);
//USART1_RX PA.10
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
GPIO_Init(GPIOA, &GPIO_InitStructure);
//Usart1 NVIC 配置
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器
//USART 初始化设置
USART_InitStructure.USART_BaudRate = bound;//一般设置为9600;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式
USART_Init(USART1, &USART_InitStructure); //初始化串口
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启ENABLE/关闭DISABLE中断
USART_Cmd(USART1, ENABLE); //使能串口
}
/*
USART1专用的printf函数
当同时开启2个以上串口时,printf函数只能用于其中之一,其他串口要自创独立的printf函数
调用方法:USART1_printf("123"); //向USART2发送字符123
*/
void USART1_printf (char *fmt, ...){
char buffer[USART1_REC_LEN+1]; // 数据长度
u8 i = 0;
va_list arg_ptr;
va_start(arg_ptr, fmt);
vsnprintf(buffer, USART1_REC_LEN+1, fmt, arg_ptr);
while ((i < USART1_REC_LEN) && (i < strlen(buffer))){
USART_SendData(USART1, (u8) buffer[i++]);
while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
}
va_end(arg_ptr);
}
RS485总线标准规定采用差分信号进行数据传输,两根线电压差+2V~+6V 表示逻辑1;两根线电压差-2V~-6V 表示逻辑0;使用差分信号能有效的减少工模干扰,2根线之间没有地。RS485的通讯距离可以达到1500m。电压低了也不会损坏电路接口。485采用总线式拓扑结构,数据的发送和接收要占用2根线,所以发送时候就不能接收,接收时候不能发,所以只能采用半双工的发送和接收数据,在软件编程时候注意区分。
虽然处理器集成了UART控制器,产生的一般是TTL电平,该电平并不符合RS485标准,所以一般我们还要外加电路将TTL信号转换为差分的485信号。常用的芯片有(MAX485、SN75LBC184、SP3485) 磁隔离的高速芯片有AD公司的 ADM2582E/ADM2587E,光隔离的芯片有国产的金升阳公司的TD301D485H 不同的芯片要看厂家的推荐参考电路和最大速度以及使用环境。
典型电路如下
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)