STM32学习笔记一、 IO模拟串行通讯

代码下载链接:实验五、USART-IO模拟.zip-嵌入式文档类资源-CSDN下载

文档下载链接:UART数据波形分析_uart波形-硬件开发文档类资源-CSDN下载

首先对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);			
		}
	}
} 

  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值