串口学习总结

1、串口协议

1. 串口232:可双向传输,全双工负逻辑电平
2. 串口358:可双向传输,4线全双工,2线单工
3. 串口485:可双向传输,4线全双工,2线单工

2、软件模拟串口

串口发送:

1、默认TX为高电平,延时
2、起始位TX写为低电平,延时
3、发送8位数据,小端在前(即发送的第1bit为8位数据最低位),延时
4、结束位Tx写为高电平,延时
注释:延时的时间需要精确计算 delay_time = 1/波特率,具体时间需要具体调试

串口接收

1、 初始化接收引脚为下降沿中断方式、
2、 配置定时器,定时的时间要根据波特率计算
3、当引脚检测到下降沿时,说明数据开始接收
4、每进入一次定时器中断服务函数,对引脚电平进行采样
5、当数据位,校验位,停止位接收完毕后,关闭定时器,等待下一次接收

3、串口接收处理的方式

1、中断接收,再分析处理(任意数据)
2、空闲中断接收+DMA(不定长数据)
3、进中断服务函数,关中断,队列接收数据,当寄存器无数据时,延时等待数据,若延时超时,开中断,退出中断服务函数(不定长数据)

软件模拟串口

#define OI_TXD	PCout(13)
#define OI_RXD	PBin(14)

#define BuadRate_9600	100

u8 len = 0;	//接收计数
u8 USART_buf[11];  //接收缓冲区

enum{
	COM_START_BIT,
	COM_D0_BIT,
	COM_D1_BIT,
	COM_D2_BIT,
	COM_D3_BIT,
	COM_D4_BIT,
	COM_D5_BIT,
	COM_D6_BIT,
	COM_D7_BIT,
	COM_STOP_BIT,
};

u8 recvStat = COM_STOP_BIT;
u8 recvData = 0;

void IO_TXD(u8 Data)
{
	u8 i = 0;
	OI_TXD = 0;  
	delay_us(BuadRate_9600);
	for(i = 0; i < 8; i++)
	{
		if(Data&0x01)
			OI_TXD = 1;  
		else
			OI_TXD = 0; 	
		
		delay_us(BuadRate_9600);
		Data = Data>>1;
	}
	OI_TXD = 1;
	delay_us(BuadRate_9600);
}
	
void USART_Send(u8 *buf, u8 len)
{
	u8 t;
	for(t = 0; t < len; t++)
	{
		IO_TXD(buf[t]);
	}
}
	
 void IOConfig(void)
 {
	GPIO_InitTypeDef  GPIO_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
 	EXTI_InitTypeDef EXTI_InitStruct;
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO|RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOC, ENABLE);	 //使能PB,PC端口时钟 
	 
	 //SoftWare Serial TXD
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;	    
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 //推挽输出
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		 //IO口速度为50MHz	 
  GPIO_Init(GPIOC, &GPIO_InitStructure);	  				
  GPIO_SetBits(GPIOC,GPIO_Pin_13); 						
	 
	 
	//SoftWare Serial RXD
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		
	GPIO_Init(GPIOB, &GPIO_InitStructure);	 

	GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource14);
	EXTI_InitStruct.EXTI_Line = EXTI_Line14;
	EXTI_InitStruct.EXTI_Mode=EXTI_Mode_Interrupt;
	EXTI_InitStruct.EXTI_Trigger=EXTI_Trigger_Falling; //下降沿触发中断
	EXTI_InitStruct.EXTI_LineCmd=ENABLE;
	EXTI_Init(&EXTI_InitStruct);


	NVIC_InitStructure.NVIC_IRQChannel= EXTI15_10_IRQn ; 
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2; 
	NVIC_InitStructure.NVIC_IRQChannelSubPriority =2;  
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;  
	NVIC_Init(&NVIC_InitStructure);  
	
}
 
void TIM4_Int_Init(u16 arr,u16 psc)
{
  TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	NVIC_InitTypeDef NVIC_InitStructure;

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); //时钟使能
	
	//定时器TIM4初始化
	TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值	
	TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
	TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure); //根据指定的参数初始化TIMx的时间基数单位
	TIM_ClearITPendingBit(TIM4, TIM_FLAG_Update);
	TIM_ITConfig(TIM4,TIM_IT_Update,ENABLE ); //使能指定的TIM3中断,允许更新中断

	//中断优先级NVIC设置
	NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;  //TIM4中断
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;  //先占优先级1级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;  //从优先级1级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
	NVIC_Init(&NVIC_InitStructure);  //初始化NVIC寄存器			 
}
 
 
 int main(void)
 {		
	 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级
	 delay_init();
	 IOConfig();
  TIM4_Int_Init(107, 71);	 //1M计数频率
	 
  while(1)
	{
		if(len > 10)
		{
			len = 0;
			USART_Send(USART_buf,11);
		}
	}
}

void EXTI15_10_IRQHandler(void)
{
	if(EXTI_GetFlagStatus(EXTI_Line14) != RESET)
	{
		if(OI_RXD == 0) 
		{
			if(recvStat == COM_STOP_BIT)
			{
				recvStat = COM_START_BIT;
				TIM_Cmd(TIM4, ENABLE);
			}
		}
		EXTI_ClearITPendingBit(EXTI_Line14);
	}
}

void TIM4_IRQHandler(void)
{  
	if(TIM_GetFlagStatus(TIM4, TIM_FLAG_Update) != RESET)
	{
		TIM_ClearITPendingBit(TIM4, TIM_FLAG_Update);	
		 recvStat++;
		if(recvStat == COM_STOP_BIT)
		{
			TIM_Cmd(TIM4, DISABLE);
			USART_buf[len++] = recvData;	
			return;
		}
		if(OI_RXD)
		{
			recvData |= (1 << (recvStat - 1));
		}else{
			recvData &= ~(1 << (recvStat - 1));
		}	
  }		
}

空闲中断

void TS_USART3_Init(void)
{
      USART_Config(3, 9600, USART_WordLength_8b, USART_Parity_No,  2,  0, ENABLE, DISABLE);
      USART3_DMA();//空闲中断+DMA
      USART3_485_En_Init();
      USART3_485_OFF();
}
//主要是第二个函数:
void USART3_DMA(void)
{
	DMA_InitTypeDef DMA_InitStructure;    
	USART_ITConfig(USART3,USART_IT_TC,  DISABLE);//关闭发送中断 
	USART_ITConfig(USART3,USART_IT_RXNE,DISABLE);//关闭接收中断!  
	USART_ITConfig(USART3,USART_IT_IDLE,ENABLE); //开启总线空闲中断 !
	USART_Cmd(USART3, ENABLE);                     // 使能 USART3
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);                      //使能DMA1时钟  
	DMA_DeInit(DMA1_Channel3);                                              //初始化DMA1通道3  串口3接收通道
	DMA_InitStructure.DMA_PeripheralBaseAddr = 0x40004804;                  //串口3接收数据的地址
	DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)GPS_Uart_Rcv_Buf;      //数据存放的复制
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;                      //数据传送方向  串口3作为数据源
	DMA_InitStructure.DMA_BufferSize = GPS_Rev_Buf_Size;                    //接收数据个数       
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;        //外围设备 串口3 地址不递增
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                 // DMA存储地址递增
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //外围设备 串口3 数据宽度 8bits
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;         //DMA存储 数据宽度 8bits
	DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;                       
//DMA_Mode_Normal(只传送一次), DMA_Mode_Circular (不停地传送)
	DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;                   //串口3通道优先为中等
	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;                            //关闭内存到内存
	DMA_Init(DMA1_Channel3, &DMA_InitStructure);
	USART_DMACmd(USART3, USART_DMAReq_Rx, ENABLE);  //使能串口3 DMA功能
	DMA_Cmd(DMA1_Channel3, ENABLE);
}
//现在就配置好了,用的是DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
//也就是中断接收数据:过来0X12,0X34,0XFF这样一串,在一串全部过来以后会掉到中断去,并且这个串已经DMA自动搬运到数组中了!
//因为我是一次,下次DMA就无效了,所以服务函数需要再起启动
void USART3_IRQHandler(void)
{
    u8 res,i;   
    if(USART_GetITStatus(USART3, USART_IT_IDLE) != RESET)        //串口3    总线空闲    
    {
      	//USART_ClearITPendingBit(USART3, USART_IT_IDLE);  //清除标记位
        res = USART3->SR;//同上
        res = USART3->DR; //清USART_IT_IDLE标志----------所谓的清空不是int a=0  而是一个数 a=->dr你拿走 它就空了
        DMA_Cmd(DMA1_Channel3, DISABLE);//关闭DMA1通道        
        Iusart3_received_handle();//去分析数组吧!!
        DMA_SetCurrDataCounter(DMA1_Channel3,GPS_Rev_Buf_Size);  //接收数据个数  
        DMA_Cmd(DMA1_Channel3, ENABLE);                          //开启DMA1通道3    
    }
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
8251串行接口是一种常用的串行通信接口芯片,它可以实现计算机与其他设备之间的数据传输,如串口通信、调制解调器通信等。在应用实验中,可以通过对8251串行接口的操作和调试,了解串行通信的基本原理和实现方法,提高学生的实践能力和理论水平。 下面是8251串行接口应用实验的分析: 1. 实验目的 掌握8251串行接口的基本工作原理和操作方法,学习串行通信的基本概念和实现方法,了解串口通信的应用场景和应用技术。 2. 实验内容 (1)了解8251串行接口的基本结构和工作原理,包括接口通信方式、寄存器功能和控制信号等。 (2)使用8251串行接口实现单向串口通信和双向串口通信,掌握串行通信的基本原理和实现方法,包括波特率、数据格式、校验码等。 (3)调试和测试串口通信的功能和性能,包括数据传输速率、数据正确性、数据丢失率等指标。 3. 实验步骤 (1)连接实验设备,包括计算机、串口线、终端设备等。 (2)配置串口参数,包括波特率、数据位数、停止位数、校验码等。 (3)编写串口通信程序,实现数据的发送和接收。 (4)进行实验测试,包括数据传输速率、数据正确性、数据丢失率等指标的测试和评估。 4. 实验结果 通过8251串行接口应用实验,可以获得以下实验结果: (1)掌握8251串行接口的基本工作原理和操作方法。 (2)了解串行通信的基本原理和实现方法,包括波特率、数据格式、校验码等。 (3)掌握串口通信的应用场景和应用技术。 (4)能够编写串口通信程序,实现数据的发送和接收。 (5)能够进行实验测试,评估串口通信的功能和性能,包括数据传输速率、数据正确性、数据丢失率等指标的测试和评估。 5. 实验总结 8251串行接口应用实验是一种重要的实践教学环节,它可以帮助学生深入了解串行通信的基本原理和实现方法,提高学生的实践能力和理论水平。在实验过程中,需要注意安全和正确操作,避免对实验设备造成损坏或影响实验结果。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值