代码下载链接:实验五、USART-IO模拟.zip-嵌入式文档类资源-优快云下载
文档下载链接:UART数据波形分析_uart波形-硬件开发文档类资源-优快云下载
首先对UART数据波形进行分析:
本文通过对一步串行数据格式的分析,阐述通过波形分析方法调试UART收发原理和方法。
经常遇到初学者,对单片机串行通讯出了问题不知道如何办的情况,起始最有效的调试方法是使用示波器观察收发数据的波形,通常观察波形可以确定一下情况:
1、是否有数据接收或发送;
2、数据是否正确;
3、波特率是否正确;
一、串行数据的格式
一步串行数据的一般格式是:起始位+数据位+停止位,其中起始位1位,数据位可以是5、6、7、8位,停止位可以是1、1.5、2位。
起始位是一个值为0的位,所以对于正逻辑的TTL电平,起始位是一位时间的低电平,停止位是值为1的位,所以对于正逻辑的TTL电平,停止位是高电平,对于负逻辑(如RS232电平)则相反。
例如,对于16进制数据55aaH,当采用8位数据位、1位停止位传输时,它在信号线上的波形如图1(TTL电平)和图2(RS232电平)所示。
图1 TTL电平的串行数据帧格式(55aaH)
图2 RS232电平的串行数据格式(55aaH)
二、根据波形图计算波特率
如图3是图1在示波器中的显示示意,其中灰色线是示波器的时间分度线,此时假设是200ms/格。
图3 波特率计算示意图
可以看到,第一个字节的10位(1位起始位、8位数据位和1位停止位)共占约1.05ms,由此可以计算出波特率约为:
10bit / 1.05ms * 1000 ≈ 9.600bit/s
如果上图中的时间轴是100ms/格,同样可以计算出波特率应是19200bit/s。
当通讯不正常,又能观察到波形时,就可根据上诉方法,从波形图计算一下波特率是否正确。
三、根据波形图判断RS-485收发数据的正确与否
RS-485是一种半双工的串行通讯方式。485电平芯片要正确接收和发送数据,必须保证控制信号和数据的同步,否则要么发送数据丢失,要么接收数据可能丢失。
RS-485发送数据时的正确时序如图4所示
图4 RS-485正确发送数据时序
在图4中,发送控制信号的宽度基本与数据信号的宽度一致,所以能保证发送数据的正确和发送后及时转为接收。
图5和图6分别是控制信号太短和控制信号太长的情况。
图5 RS-485控制信号太短时的时序
图6 RS-485控制信号太长时的时序
在图5中,由于控制信号关闭过早,则第二个字节的后两位将发送错误;在图6中,由于控制信号关闭过迟,使485芯片在发生数据后,不能及时转到接收状态,此时总线若有数据过来,则本单元将不能挣钱接收。
在IO模拟UART时,首先要已知的量有波特率,一个字节10位(1位起始位、8位数据位、1位停止位),按9600bit/s发送数据时,帧与帧之间的时间间隔为:
T = 10bit / 9600bit /s * 1000ms = 1.04ms
发送采用IO模拟时序图,接收采用IO下降沿中断,检测到停止位后关闭IO中断,接收完后9位开启IO中断;
serial.c
#include "Serial.h"
#include "hal_sys.h"
#include "usart.h"
#include "protocol.h"
/**
* @brief 模拟串行通讯 输入引脚初始化
* @param
* @retval
*/
void Serial_Rx_Init(void)
{
GPIO_EXTILineConfig(GPIO_PortSourceGPIOD,GPIO_PinSource2);
GPIO_Common_Config(GPIOC,GPIO_Pin_12,GPIO_Speed_50MHz,GPIO_Mode_Out_PP);
GPIO_Common_Config(GPIOD,GPIO_Pin_2,GPIO_Speed_50MHz,GPIO_Mode_IPU);
NVIC_Common_Config(EXTI2_IRQn,0x02,0x02);//Rx
EXTI_Common_Config(EXTI_Line2,EXTI_Mode_Interrupt,EXTI_Trigger_Falling,ENABLE);//下降沿
EXTI_ClearITPendingBit(EXTI_Line2);
}
/**
* @brief 模拟串行通讯的开始位
* @param time 时间
* @retval
*/
void Serial_Write_Start_Bit(u32 time)
{
Tx_Pin() = 0;
delay_us(time);
}
/**
* @brief 模拟串行通讯的停止位
* @param time 时间
* @retval
*/
void Serial_Write_Stop_Bit(u32 time)
{
Tx_Pin() = 1;
delay_us(time);
}
/**
* @brief 模拟串行通讯的数据位
* @param[i] data 数据
* @param[i] time 时间
* @retval
*/
void Serial_Write_Data(u8 data,u32 time)
{
u8 i,bit;
Serial_Write_Start_Bit(time);
for(i=0;i<8;i++)
{
bit = (data >> i) & 0x01;
if(bit ==0)Tx_Pin() = 0;
else Tx_Pin() = 1;
delay_us(time );
}
Serial_Write_Stop_Bit(time);
}
/**
* @brief 发送模拟串行通讯的数据
* @param[i] data 数据缓存
* @param[i] time 时间
* @retval
*/
void Serial_Write_String(u8 *data,u8 len,u32 time)
{
u8 i;
for(i=0;i<len;i++)
{
Serial_Write_Data(data[i],time);
}
}
/**
* @brief 读取模拟串行通讯的数据
* @param[i] data 数据缓存
* @param[i] time 时间
* @retval
* 可修改为中断获取起始位
*/
u8 Seroal_Read_Data(u32 time)
{
u8 i = 9,data;
if(Rx_Pin() == 0)
{
delay_us(time);//开始位
while(i--)
{
data >>=1;
if(Rx_Pin() == 1)data |=0x80;
delay_us(time);
}
}
return data;
}
u8 data;
/**
* @brief 外部中断
* @param
* @retval
*/
void EXTI2_IRQHandler(void)
{
u8 i =9;
if(EXTI_GetITStatus(EXTI_Line2) != RESET)
{
NVIC->ICER[EXTI2_IRQn >> 0x05] =
(uint32_t)0x01 << (EXTI2_IRQn& (uint8_t)0x1F); //失能中断
EXTI_ClearITPendingBit(EXTI_Line2);
delay_us(30);//开始位
while(i--)
{
data >>=1;
if(Rx_Pin() == 1)data |=0x80;
delay_us(104);
}
UOCS_Protocol_Receive(USART1,&USART1_Buffer,data);
}
EXTI_ClearITPendingBit(EXTI_Line2);
NVIC->ISER[EXTI2_IRQn >> 0x05] =
(uint32_t)0x01 << (EXTI2_IRQn & (uint8_t)0x1F);
}
Serial.h
#ifndef __SERIAL_H
#define __SERIAL_H
#include "hal_delay.h"
#include "hal_sys.h"
#define Tx_Pin() PCout(12)
#define Rx_Pin() PDin(2)
void Serial_Rx_Init(void);
void Serial_Write_Start_Bit(u32 time);
void Serial_Write_Stop_Bit(u32 time);
void Serial_Write_Data(u8 data,u32 time);
void Serial_Write_String(u8 *data,u8 len,u32 time);
u8 Seroal_Read_Data(u32 time);
#endif
main.c
int main(void)
{
u16 time =0,j=0,i;
APP_BSP_Init();
while(1)
{
if(Public_Struct.Time_Struct->SCycle ==TRUE)
{
Public_Struct.Time_Struct->SCycle = FALSE;
Serial_Write_String(USART1_Buffer.sendbuff,USART1_Buffer.send_size,104);
}
}
}