精华内容
下载资源
问答
  • IO模拟串口时序
    千次阅读
    2021-12-16 17:14:09

    STM32的IO模拟串口

    一、为什么要用STM32的普通IO口模拟串口?

    随着工程的增大,开发者们可能在一开始不能完全利用好STM32的资源,造成串口资源不足。例如:STM32F103C8T6只有3个串口,在不改动硬件资源的情况下,因此只能想到用IO口模拟串口的时序。

    二、参考程序

    代码如下(示例):

    IO2USART.c

    #include "IO2USART.h"
    /**
    *软件串口的实现(IO模拟串口)
    * 波特率:9600    1-8-N
    * TXD : PB4
    * RXD : PB5
    * 使用外部中断对RXD的下降沿进行触发,使用定时器4按照9600波特率进行定时数据接收。
    * Demo功能: 接收11个数据,然后把接收到的数据发送出去
    */
    #define BuadRate_9600	100
    u8 len = 0;	//接收计数
    u8 USART_buf[11];  //接收缓冲区
    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, ENABLE);	 //使能PB,PC端口时钟 
      GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE); 
    	 //SoftWare Serial TXD
     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;	    
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 //推挽输出
      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		 //IO口速度为50MHz	 
      GPIO_Init(GPIOB, &GPIO_InitStructure);	  				
      GPIO_SetBits(GPIOB,GPIO_Pin_4); 						
    	 
    	 
    	//SoftWare Serial RXD
    	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
       GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
       GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		
    	GPIO_Init(GPIOB, &GPIO_InitStructure);	 
    
    	GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource5);
    	EXTI_InitStruct.EXTI_Line = EXTI_Line5;
    	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= EXTI9_5_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寄存器			 
    }
     
    void EXTI9_5_IRQHandler(void)
    {
    	if(EXTI_GetFlagStatus(EXTI_Line5) != RESET)
    	{
    		if(OI_RXD == 0) 
    		{
    			if(recvStat == COM_STOP_BIT)
    			{
    				recvStat = COM_START_BIT;
    				TIM_Cmd(TIM4, ENABLE);
    			}
    		}
    		EXTI_ClearITPendingBit(EXTI_Line5);
    	}
    }
    
    
    

    总结

    提示:亲测稳定运行,需要完整工程联系QQ:2858054751

    更多相关内容
  • 串口是一个广义的概念,这是单讲单片机的串口UART,以及单片机的TTL电平,主要是记录一下自己忘了还能再看一下。 1、TTL电平标准 输出 L: <0.8V ; H:>2.4V。 输入 L: <1.2V ; H:>2.0V TTL器件...

    串口是一个广义的概念,这是单讲单片机的串口UART,以及单片机的TTL电平,主要是记录一下自己忘了还能再看一下。

    1、TTL电平标准

    输出 L: <0.8V ; H:>2.4V。

    输入 L: <1.2V ; H:>2.0V

    TTL器件输出低电平要小于0.8V,高电平要大于2.4V。输入,低于1.2V就认为是0,高于2.0就认为是1。于是TTL电平的输入低电平的噪声容限就只有(0.8-0)/2=0.4V,高电平的噪声容限为(5-2.4)/2=1.3V。

    2、UART通信时序

     引用一张网图,单说上面的ttl电平,发送一个字节数据,需要1个起始位,8个数据位以及1个停止位,共发送10bit,起始位是低电平,停止位用高电平。假设波特率是37600,那么发送1bit的时间就是1000000/37600约等于26us,高电平保持26us就是1,低电平保持26us就是0,通常低位先发。比如a3h,则是b1100(3) 0101(a)。

    展开全文
  • GPIO模拟UART串口时序

    万次阅读 2018-05-03 00:23:40
    GPIO模拟UART串口时序模拟时序:平台:Cortex-M0与FPGA UART的区别: FPGA发送、接收使用的是独立的时序,并行处理易于实现。而单片机只能使用定时器来模拟时序,并通过外部下降沿中断触发启动,实时性受到限制;...

    GPIO模拟UART串口时序

    模拟时序:

    平台:Cortex-M0

    与FPGA UART的区别:

      FPGA发送、接收使用的是独立的时序,并行处理易于实现。而单片机只能使用定时器来模拟时序,并通过外部下降沿中断触发启动,实时性受到限制;对于实时性要求较高的应用,需要同时处理发送和接收时(全双工)1路UART需要使用2个定时器;而半双工应用可以只使用一个定时器即可实现。基于50MHZ的M0一般9600是可以实现的,在向上估计会不稳定。主要是应用于对于特定设计临时增加低速串口通信,降低成本。

    示例代码:

    V1.5:双定时器方案

    1、myiouart.h+ myiouart.c

    2、资源占用:1个输入中断+2个定时器(针对实时要求高的场合)

    myiouart.h:
    //<<< Use Configuration Wizard in Context Menu >>>
    #ifndef _MYIOUART_H_
    #define _MYIOUART_H_
    #include "LPC11xx.h"
    
    //<h> MyIouartConfig [2017.2.20]
    //<i>   注:双定时器模拟串口!CT32B0+CT32B1
    	//<o>ECHO <0=> No <1=> Yes
    	//<i>回显测试功能: 
    	//<i>打开回显功能后,模拟串口将自动返回自己所接收到的数据,仅作测试串口功能使用!
    	#define ENABLE_ECHO 	0					 
    
    	//<o> COM_BAUDRATE <1200=> 1200 <9600=> 9600  <57600=> 57600  <115200=> 115200
    	//<i> 串口通讯波特率配置
    	//<i> 默认为9600!
    	#define IOUART_BAUDRATE	9600
    
    
    //</h>
    
    
    //--------------------------------------------------------------
    #define IOUART_RECV_NULL 0         //没有接收数据
    #define IOUART_RECV_OK 1           //接收数据成功返回值
    #define IOUART_RECV_WRONG_ST 11    //接收数据起始位出错返回值
    #define IOUART_RECV_WRONG_EN 12    //接收数据结束位出错返回值
    
    //
    #define   SET_UART_BAUD   48000000UL/(IOUART_BAUDRATE) //波特率设置
    #define   MyUart_STOPBITS 1
    
    
    
    //
    
    //config  iouart3
    #define  MyIOUART_TX_PORT      PIO2_8
    #define  MyIOUART_RX_PORT      PIO2_7
    #define  MyIOUART_TX_P         LPC_GPIO2
    #define  MyIOUART_RX_P         LPC_GPIO2
    #define  MyIOUART_TX_P_INDEX   8
    #define  MyIOUART_RX_P_INDEX   7
    //
    #define  MyIOUART_RX_IRQn   EINT2_IRQn
    
    
    //------------------------------------------
    
    extern char g_strtemp[32];	
    extern unsigned long g_rx_cnt;//For Debug. Record the count value of recieved bytes!
    extern unsigned long g_tx_cnt;//For Debug. Record the count value of sended bytes!
    
    
    //
    #define BUFFER_LEN 128
    
    //
    char* NumToStrEx(long Number,char*PStr,unsigned char Len);
    //FIFO Buffer
    void Iouart_FifoInit(void);
    unsigned char GetLen_RecvedData(void);
    unsigned char* GetTxbuf_RecvedData(void);
    unsigned char ReadByte_RxFiFo(void);
    int WriteByte_TxFifo(unsigned char *T,unsigned char len);//非阻塞
    
    //
    void put_char(char *cp);//阻塞
    void iouart1_send(char *pData,unsigned char pLen);//阻塞
    void print_dat(char sp[],char len);//阻塞
    //
    void IOUART1_Init(void);
    
    void Timer2Init(void);
    void Timer3Init(void);
    
    
    
    
    
    //--------------------------------------------------------------
    #endif
    // <<< end of configuration section >>>
    
    
    myiouart.c:
    
    #include "myiouart.h"
    //
    char g_strtemp[32]={0};	
    unsigned long g_rx_cnt = 0;//For Debug. Record the count value of recieved bytes!
    unsigned long g_tx_cnt = 0;//For Debug. Record the count value of sended bytes!
    
    //RX
    static volatile unsigned char l_recv_byte=0;
    static volatile unsigned char l_recv_st=0;
    static volatile unsigned char l_recv_cnt=8;
    
    //TX
    static volatile unsigned char l_send_byte=0;
    static volatile unsigned char l_send_st=0;
    static volatile unsigned char l_send_cnt=8;
    static volatile unsigned char l_send_style=0;//根据send_style判断是通过缓存发送还是直接发送
    
    //
    static volatile unsigned char l_channel=0;
    //
    //l=local g=global  
    //FIFO Buffer
    unsigned char l_Txbuffer[8+BUFFER_LEN]={0};
    volatile unsigned char l_Rxbuffer[8+BUFFER_LEN]={0};
    volatile unsigned char l_RxDataLen=0;
    volatile unsigned char l_RxWrongRecord[2+BUFFER_LEN]={0};//接收数据出错记录BUFFER
    //
    void Iouart_FifoInit(void)
    {
    	//仅记录一个BUFFER_LEN长度的接收错误记录
    	l_RxWrongRecord[0]=2;//sp:2->(2+BUFFER_LEN)-1
    	l_RxWrongRecord[1]=(2+BUFFER_LEN)-1;//end addr
    	//
    	l_RxDataLen=0;
    	
    	//Rx
    	//接收数据的起始地址(使用相对地址从8->BUFFER_LEN-1)
    	l_Rxbuffer[0]=8;
    	l_Rxbuffer[1]=0;
      //接收数据的结束地址
    	l_Rxbuffer[2]=8;
    	l_Rxbuffer[3]=0;
    	//Buffer的结束地址
      l_Rxbuffer[4]=(BUFFER_LEN-1)+8;
    	l_Rxbuffer[5]=0;
    	//接收数据的长度
    	l_Rxbuffer[6]=0;
    	//Buffer的长度
    	l_Rxbuffer[7]=BUFFER_LEN;
    	
    	//Tx
    	//Tx数据的起始地址
    	l_Txbuffer[0]=8;
    	l_Txbuffer[1]=0;
      //Tx数据的结束地址
    	l_Txbuffer[2]=8;
    	l_Txbuffer[3]=0;
    	//Buffer的结束地址
      l_Txbuffer[4]=(BUFFER_LEN-1)+8;
    	l_Txbuffer[5]=0;
    	//Tx数据的长度
    	l_Txbuffer[6]=0;
    	//Buffer的长度
    	l_Txbuffer[7]=BUFFER_LEN;
    	
    }
    
    /*
    获取Buffer中接收到的数据长度
    */
    unsigned char GetLen_RecvedData(void)
    {
       return l_RxDataLen;
    }
    
    unsigned char* GetTxbuf_RecvedData(void)
    {
       return l_Txbuffer;
    }
    /*
     从模拟串口读取一个字节数据 
     调用该函数前先判断GetRecvDataLen()返回值,否则在没有接收到数据时读到的数据为0
    */
    unsigned char ReadByte_RxFiFo(void)
    {
    	unsigned char Data0=0;
    	if(l_Rxbuffer[6])
    	{
    		 Data0 = l_Rxbuffer[l_Rxbuffer[0]];
    		 //
    		 if(l_Rxbuffer[0]< l_Txbuffer[4])
    		 {
    		   l_Rxbuffer[0]++;
    		 }
    		 else
    		 {
    			 l_Rxbuffer[0]=8;
    		 }
    		 //
    		 l_Rxbuffer[6]--;
    	}
      //update rx len
    	l_RxDataLen=l_Rxbuffer[6];
    	
      return Data0;
    }
    
    /*
     从模拟串口发送一个数据Buffer,属于一次性连续发送!
     若发送缓冲区满返回-1
    */
    int WriteByte_TxFifo(unsigned char *T,unsigned char len)
    {
      unsigned char i = 0;
    	if(len)
    	while(len--){
    	if(l_Txbuffer[6] < l_Txbuffer[7]) {
         l_Txbuffer[6]++;//TxLength
    		 l_Txbuffer[l_Txbuffer[2]]=T[i++];
    		 if(l_Txbuffer[2]<l_Txbuffer[4])
    		 {
    			 l_Txbuffer[2]++;
    		 }
    		 else
    		 {
    			 l_Txbuffer[2]=8;
    		 }
    	 }
    	 else
       {
         return -1;//发送缓冲区满
       }	
    	}
    		 
    	 //开启发送需设置5个变量
    	 l_send_byte = l_Txbuffer[l_Txbuffer[0]];
    	 l_send_cnt = 9;
    	 l_send_style=1;	
       LPC_TMR32B0->TCR = 1;
    	 l_send_st=1;
    
       //-----------
       return 1;
    	
    }
    
    
    
    /*
      数字转字符串函数
    */
    char* NumToStrEx(long Number,char*PStr,unsigned char Len)
    {
    	unsigned long NumberT=0;
    	unsigned char Count=0;
    	if(Number<0)  
    	{
    		*PStr='-';
    		Number=-Number;
    		Count=1;
    	}
    	else if(Number==0)
    	{
    	  *PStr='0';
    		*(PStr+1)=0;
    		return PStr;
    	}
    	NumberT=Number;
    	while(NumberT)
    	{
    	   	 NumberT/=10;
    		 Count++;
    	}
    	if(Len<=Count)  return 0;
    	//
    	*(PStr+Count--)=0;
    	//
    	while(Number)
    	{
    		*(PStr+Count--)='0'+Number%10;
    		Number/=10;
    	}
    	return PStr;
    }
    
    void put_char(char *cp)
    {
        //LPC_GPIO2->IE &= ~(1<<7);LPC_GPIO2->IC=(1<<7); //NVIC_DisableIRQ(EINT2_IRQn);
    	  //LPC_GPIO3->IE &= ~(1<<1);LPC_GPIO3->IC=(1<<1);
    	  //---------------------------------------------
      	
    		l_send_byte = *cp;	
    		l_send_cnt = 9;
    		l_send_style = 0;
      	l_send_st=1;
    		// LPC_TMR16B1->TCR = 1;//start counter 
    	  LPC_TMR32B0->TCR = 1;//根据使用的定时器选择
    		while(l_send_st){}
    
    	  //--------------------------------------------
    	
    	  //LPC_GPIO2->IE |= (1<<7);
    	  //NVIC_EnableIRQ(EINT2_IRQn); 
    	  //LPC_GPIO3->IE |= (1<<1);
    
    }
    
    
    /*
        阻塞发送字符串,不使用缓存
    */
    void iouart1_send(char *pData,unsigned char pLen)
    {
    	while(pLen--)
    	{
    		put_char(pData++);
    	}
    }
    
    /*
        阻塞发送数据,不使用缓存
    */
    void print_dat(char sp[],char len)
    {
      LPC_GPIO0->DATA |= (1 << 7);//H	485TxMode
    	//-----------------------------------------
    	while(len--)
    	{
    		put_char(sp++);
    	}
    	//-----------------------------------------
    	LPC_GPIO0->DATA &= ~(1 << 7);	//L	485RxMode	
    }
    
    
    void IOUART1_Init(void)
    {
    	Iouart_FifoInit();
    	//
    	LPC_SYSCON->SYSAHBCLKCTRL |= (1ul << 6); 
    	//UART3 [channel=0] & 4852  EN--P0.7   RX--P2.7  TX--P2.8 
    	//TX PIO2_8
    	LPC_IOCON->MyIOUART_TX_PORT &= ~(0x07);	/*IO功能*/
    	MyIOUART_TX_P->DIR  |= (1 << MyIOUART_TX_P_INDEX);	/*Output*/
    	MyIOUART_TX_P->DATA |= (1 << MyIOUART_TX_P_INDEX);//H	
    	//RX  PIO2_7    
    	LPC_IOCON->MyIOUART_RX_PORT &= ~(0x07);//IO fucntion 
    	MyIOUART_RX_P->DIR &= ~(1<<MyIOUART_RX_P_INDEX);//Input
    	MyIOUART_RX_P->IS  &= ~(1<<MyIOUART_RX_P_INDEX);//edge sensitive
    	MyIOUART_RX_P->IEV &= ~(1<<MyIOUART_RX_P_INDEX);//falling edge 
    	MyIOUART_RX_P->IBE &= ~(1<<MyIOUART_RX_P_INDEX);//
    	//
    	NVIC_SetPriority(MyIOUART_RX_IRQn, 0);
    	NVIC_EnableIRQ(MyIOUART_RX_IRQn);
    	MyIOUART_RX_P->IC=(1<<MyIOUART_RX_P_INDEX);
    	MyIOUART_RX_P->IE |= (1<<MyIOUART_RX_P_INDEX);//enable interrupt
    	
    	//sel uart chanel
    	l_channel=0;
    	g_rx_cnt=0;
    	g_tx_cnt=0;
    	
    	//
    	Timer3Init();//CT32B1  For Rx!
    	Timer2Init();//CT32B0  For TX!
    }
    
    
    
    void RecvWrongSt(void)
    {		
    	 //记录错误,并重新开启RX引脚接收中断
    	 LPC_GPIO3->DATA &= ~(1 << 3);//L	
    	 //Record wrong case.Just For Debug.
    	 l_RxWrongRecord[l_RxWrongRecord[0]]=IOUART_RECV_WRONG_ST;
    	 if(l_RxWrongRecord[0]<l_RxWrongRecord[1])
    	 {
    		 l_RxWrongRecord[0]++;
    	 }
    	 //		 
    	 MyIOUART_RX_P->IC |= (1<<MyIOUART_RX_P_INDEX);				 
    	 MyIOUART_RX_P->IE |= (1<<MyIOUART_RX_P_INDEX);
    	 return;		
    }
    
    void  recv_interrupt(void) //Just For Echo!
    {
      //回显测试 
      unsigned char len = l_RxDataLen;	
    	while(len--)
    	{
        unsigned char t= ReadByte_RxFiFo();
        WriteByte_TxFifo(&t,1);
      }  
    }
    
    
    
    void PIOINT2_IRQHandler(void)//下降沿触发中断
    {
      LPC_GPIO3->DATA |= (1 << 3);//H  //LED
    	//
    	if((MyIOUART_RX_P->DATA & (1<<MyIOUART_RX_P_INDEX)))//起始位电平(L)检测
    	{
    	  RecvWrongSt();
        return;
    	}
    	//
    	if(MyIOUART_RX_P->MIS&(1<<MyIOUART_RX_P_INDEX))//Rx 判断触发中断的引脚
    	{		 
           //
    		   MyIOUART_RX_P->IE &= ~(1<<MyIOUART_RX_P_INDEX);//disable interrupt
    	     MyIOUART_RX_P->IC |= (1<<MyIOUART_RX_P_INDEX);//clear interrupt flag
    		   //
    		   //
    		   l_RxDataLen = 0;//接收过程禁止读取数据
    		   l_recv_cnt = 8;
    			 l_recv_st = 1;
    		   // start recv
           LPC_TMR32B1->TCR = 1;
    			 LPC_TMR32B1->IR = 1;
    			
    			 //
    			 //LPC_GPIO2->IC=(1<<7);//clear interrupt flag
    			 //LPC_GPIO2->IE |= (1<<7);//enable interrupt
    			 //NVIC_EnableIRQ(EINT2_IRQn);
    			 //
    	 }
    	 //
       LPC_GPIO3->DATA &= ~(1 << 3);//L	
    }
    
    
    //32位定时器  CT32B0/1  【注:32位定时器和16位定时器功能一样,仅仅将16改成32,并修改一下时钟使能位(C32B0=9;C32B1=10),即可】
    void Timer2Init(void)//CT32B0
    {
      LPC_SYSCON->SYSAHBCLKCTRL	|= (1<<9); //enable ct32b1 clk 
      LPC_TMR32B0->CTCR &= ~(3);//timer[function sel]
    	LPC_TMR32B0->MCR = 3;//enable interrupt and reset autoself
    	//-------------------------------------------------------------
    	LPC_TMR32B0->PR = 0;//16bits[max=2^16=65536]  48MHZ(sysahbclk)/48=1000KHZ
    	//IOuart要支持高的波特率,PR值要设置尽量小,然后不断调试MR0的值即可达要想要的波特率,一开始
    	//调试不成功就是因为PR设为了100太大,导致9600接收总是失败
    	//-------------------------------------------------------------
    	//One timer can gennerate four interrupts for MR0、MR1、MR2、MR3.
    	LPC_TMR32B0->MR0 = SET_UART_BAUD;
    	//--------------------------------------------------------------
    	LPC_TMR32B0->TCR = 2;//reset 
    	LPC_TMR32B0->IR =1;//clear interrupt flag
    	LPC_TMR32B0->TCR = 1;//load cfg of ct16b1
    	//
    	LPC_TMR32B0->TCR =2 ;//reset
    	LPC_TMR32B0->TCR =0 ;//stop counter
    	 
    	//
    	NVIC_EnableIRQ(TIMER_32_0_IRQn);	
        NVIC_SetPriority(TIMER_32_0_IRQn,1);	
    	
    }
    
    void Timer3Init(void)//CT32B1
    {
    	LPC_SYSCON->SYSAHBCLKCTRL	|= (1<<10); //enable ct32b1 clk 
    	LPC_TMR32B1->CTCR &= ~(3);//timer[function sel]
    	LPC_TMR32B1->MCR = 3;//enable interrupt and reset autoself
    	//-------------------------------------------------------------
    	LPC_TMR32B1->PR = 0;//10;//16bits[max=2^16=65536]  48MHZ(sysahbclk)/48=1000KHZ
    	//IOuart要支持高的波特率,PR值要设置尽量小,然后不断调试MR0的值即可达要想要的波特率,一开始
    	//调试不成功就是因为PR设为了100太大,导致9600接收总是失败
    	//-------------------------------------------------------------
    	//One timer can gennerate four interrupts for MR0、MR1、MR2、MR3.
    	LPC_TMR32B1->MR0 = SET_UART_BAUD;
    	//--------------------------------------------------------------
    	LPC_TMR32B1->TCR = 2;//reset 
    	LPC_TMR32B1->IR =1;//clear interrupt flag
    	LPC_TMR32B1->TCR = 1;//load cfg of ct16b1
    	//
    	LPC_TMR32B1->TCR =2 ;//reset
    	LPC_TMR32B1->TCR =0 ;//stop counter
    	//
    	NVIC_EnableIRQ(TIMER_32_1_IRQn);	
    	NVIC_SetPriority(TIMER_32_1_IRQn,1);	
    }
    
    //
    void TIMER32_0_IRQHandler (void)//For send destination.
    {
       
        static unsigned char  tx_k=0;
        //
        unsigned char tx_s2;
    	 
        //
        LPC_GPIO0->DATA &= ~(1 << 3);//L LED
        LPC_TMR32B0->IR =1;//clear interrupt flag
    
      
        //TX
    		if(l_send_st){
    				if(l_send_cnt)
    				{
    						if(l_send_cnt == 9)//start bit
    						{
    								if(l_channel==0)
    								{
    										MyIOUART_TX_P->DATA &= ~(1 << MyIOUART_TX_P_INDEX);//L
    								}
    								else if(l_channel==1)
    								{ }
    								else if(l_channel==2)
    								{ }
    								l_send_cnt=8;
    						}
    						else
    						{
    								switch(l_send_cnt)
    								{
    											case 8:
    													tx_s2=0x01;
    													break;
    											case 7:
    													tx_s2=0x02;
    													break;
    											case 6:
    													tx_s2=0x04;
    													break;
    											case 5:
    													tx_s2=0x08;
    													break;
    											case 4:
    													tx_s2=0x10;
    													break;
    											case 3:
    													tx_s2=0x20;
    													break;
    											case 2:
    													tx_s2=0x40;
    													break;
    											case 1:
    													tx_s2=0x80;tx_k=0;
    													break;
    											default:
    													tx_s2=0x0;
    													break;
    								}
    								//-------------------------------------------------------------
    								if(l_channel==0)
    								{//TX
    										if(!(l_send_byte&tx_s2)) MyIOUART_TX_P->DATA &= ~(1 << MyIOUART_TX_P_INDEX);//L
    										else MyIOUART_TX_P->DATA |= (1 << MyIOUART_TX_P_INDEX);//H
    								}
    								else if(l_channel==1)
    								{ }
    								else if(l_channel==2)
    								{ }
    								//
    								l_send_cnt--;
    						}
    				}
    				else
    				{
    						if(tx_k<=(MyUart_STOPBITS-1)) //1->两位停止位  0->1位停止位
    						{
    								if(l_channel==0)
    								{   MyIOUART_TX_P->DATA |= (1 << MyIOUART_TX_P_INDEX);//H
    								}
    								else if(l_channel==1)
    								{ }
    								else if(l_channel==2)
    								{ }
    								//
    								tx_k++;
    						}
    						else
    						{
    							tx_k=0;l_send_cnt  = 9;
    							if(l_send_style)//如果是FIFO发送
    							{
    									l_send_style=0;
    									//一个字节发送完
    									l_Txbuffer[6]--;
    									if(l_Txbuffer[0]<l_Txbuffer[4])  l_Txbuffer[0]++;
    									else    l_Txbuffer[0]=8;
    									//判断是否继续发送
    									if(l_Txbuffer[6])
    									{//连续发送
    											//restart timer
    											l_send_byte = l_Txbuffer[l_Txbuffer[0]];
    											l_send_cnt  = 9;
    											l_send_st = 1;
    											l_send_style = 1;	
    						
    									}
    									else
    									{
    									  l_send_style = 0;	
                        //修改点1:此处导致出现最后一个字节发送两次!需添加:
    									  l_send_st=0; //reset	
    										//reset timer	
    										LPC_TMR32B0->TCR =2;//[0-stop counter  1-start  2-reset]
    										LPC_TMR32B0->IR = 1;		  
    									
    									}
    							}
    							else
    							{
    								l_send_st=0; //reset	
    								//reset timer	
    								LPC_TMR32B0->TCR =2;//[0-stop counter  1-start  2-reset]
    								LPC_TMR32B0->IR = 1;		  
    							}
    						}
    				}
        }
    
    		//--------------------------------
        LPC_GPIO0->DATA |= (1 << 3);//LED
    }
    
    
    
    
    
    
    //
    void TIMER32_1_IRQHandler (void)//For Receive destination.
    {
        static unsigned char  rx_k=0;
    	  static char  stc_recv_check=0;//静态变量
    		static char  rx_interrupt_flag=0;
    	  //
        unsigned char rx_s1;
        //
        LPC_GPIO0->DATA &= ~(1 << 3);//L LED
        LPC_TMR32B1->IR =1;//clear interrupt flag
       	///
    		//RX
        if(l_recv_st)
        {
            if(l_recv_cnt)
    				{
    						switch(l_recv_cnt)
    						{
    										case 8:
    														rx_s1=0;l_recv_byte=0;
    												break;
    										case 7:
    														rx_s1=1;
    												break;
    										case 6:
    														rx_s1=2;
    												break;
    										case 5:
    														rx_s1=3;
    												break;
    										case 4:
    														rx_s1=4;
    												break;
    										case 3:
    														rx_s1=5;
    												break;
    										case 2:
    														rx_s1=6;
    												break;
    										case 1:
    														rx_s1=7;rx_k=0;stc_recv_check=0;
    												break;
    										default:
    														rx_s1=0;
    										 break;
    						}
    						//-------------------------------------------------------------
    						if(l_channel==0)
    						{//Rx
    							if(MyIOUART_RX_P->DATA & (1<<MyIOUART_RX_P_INDEX))  l_recv_byte+=(1<<rx_s1);
    						}
    						else if(l_channel==1)
    						{ }
    						else if(l_channel==2)
    						{ }
    						//
    						l_recv_cnt--;
    			 }
    			 else
    			 {
    					  if(rx_k<=(MyUart_STOPBITS-1)) //1->两位停止位  0->1位停止位
    						{
    								if(l_channel==0)
    								{//Rx 
    										if(MyIOUART_RX_P->DATA & (1<<MyIOUART_RX_P_INDEX))//检测停止位(H)判断
    										{  
    										    //stc_recv_check = IOUART_RECV_OK;	 
                            stc_recv_check += 2;	
                            stc_recv_check += rx_k;											
    										}
    										else
    										{ 
        										stc_recv_check +=3;	
    											  //stc_recv_check = IOUART_RECV_WRONG_EN; 
    										}
    								}
    								else if(l_channel==1)
    								{ }
    								else if(l_channel==2)
    							  { }
    								//
    								rx_k++;
    						}
    						else
    						{
    							  rx_k=0;l_recv_cnt = 8;
    							  
    							  if(stc_recv_check <= 5)
    								{
    								  stc_recv_check = IOUART_RECV_OK;	
    								
    								}
    								else
                    {
    								 stc_recv_check = IOUART_RECV_WRONG_EN; 
    								}									
    							
    								switch(stc_recv_check)
    								{
    										case IOUART_RECV_OK://成功接收一个字节
    													g_rx_cnt++;
    										      if(l_Rxbuffer[6] < l_Rxbuffer[7])//RxLength
    													{
    															l_Rxbuffer[6]++;
    															l_Rxbuffer[l_Rxbuffer[2]]=l_recv_byte;
    															if(l_Rxbuffer[2] < l_Rxbuffer[4])
    															{
    																	l_Rxbuffer[2]++;
    															}
    															else
    															{
    																	l_Rxbuffer[2]=8;
    															}
    															//连续接收时要精确控制停止位
    															if(l_channel==0)
    															{
    																	if(MyIOUART_RX_P->DATA & (1<<MyIOUART_RX_P_INDEX))
    																	{
    																			l_recv_st=0; 
    																		  rx_interrupt_flag = 1;//模拟串口的接收中断
    																	}
    																	else//检测到下一字节的起始位
    																	{//连续接收	
    																		  //连续收暂时不改变接收缓冲区的数据长度.//l_RxDataLen = 0;//注:连续接收时读取RX缓存区必须使其返回为0,否则会影响数据的接收!
    																			//l_recv_byte = 0;//必须清零,因为接收的结果是通过叠加的方式获得的
    																			l_recv_cnt = 8;
    																			l_recv_st = 1;
    																	}
    															}
    															else if(l_channel==1)
    															{ }
    															else if(l_channel==2)
    															{ }
    														 
    													}
    													else//接收缓存区满
    													{
    															l_recv_st=0;
    													}
    																									
    													break;
    										case IOUART_RECV_WRONG_EN:
    														 //Record wrong case.Just For Debug.
    														 l_RxWrongRecord[l_RxWrongRecord[0]]=IOUART_RECV_WRONG_EN;
    														 if(l_RxWrongRecord[0]<l_RxWrongRecord[1])
    														 {
    																 l_RxWrongRecord[0]++;
    														 }
    														 //
    														 l_RxWrongRecord[l_RxWrongRecord[0]]=l_recv_byte;
    														 if(l_RxWrongRecord[0]<l_RxWrongRecord[1])
    														 {
    																 l_RxWrongRecord[0]++;
    														 }
    														 //
    	                           l_recv_st=0;
    												 break;
    										default:
    											   l_recv_st=0;
    												 break;
    								}
    								//
    								if(l_recv_st==0)
    								{
    										//开RX引脚中断
    										MyIOUART_RX_P->IC |= (1<<MyIOUART_RX_P_INDEX); //clear flag
    										MyIOUART_RX_P->IE |= (1<<MyIOUART_RX_P_INDEX); //enable interrupt
    										//update len
    										l_RxDataLen = l_Rxbuffer[6];
                        //
    									  //reset timer	
    									  LPC_TMR32B1->TCR = 2;//[0-stop counter  1-start  2-reset]
    									  LPC_TMR32B1->IR = 1;
    
    								}
    						}
    			  }
        }
    		//--------------------------------
        LPC_GPIO0->DATA |= (1 << 3);//LED
    		//	
    		#if ENABLE_ECHO
        if(rx_interrupt_flag)
        {
    			rx_interrupt_flag = 0;//
    			recv_interrupt();//此函數必須立即返回!(用于回显测试)   
        }
    	  #endif
    }
    
    /*
    */
    
    /*USE EXAMPLE:
    */
    
    


    V1.6:单定时器方案

    1、DrvIOUART.h+DrvIOUART.c+DrvIOUART1.h+DrvIOUART1.c;蓝色文件为库文件,绿色文件为实例化参考

    2、资源占用:1个输入中断+1个定时器(针对实时要求不高的场合)

          文件详细见下载,末尾。

    使用小技巧:

    软件中,对.h文件的第一行添加"//<<< Use Configuration Wizard in Context Menu >>>",可使用其自带的配置功能,方便参数灵活设置。

    附录:

    1、IOUART模拟串口调试记录

      2016/10/20

    1、波特率可调节:支持收发波特率1200->57600

    [注: r字符进行回显测试,9600才能稳定不出错]

      

    19200(停止位为1)时:(单按时回显正常,按住不放回显会出错)

    停止位为2时,情况一样。

    结论:ZLG的模拟串口可以支持到57600,但连续接收数据过快时,baud>9600易出错。

    2、两路模拟串口实现

    两路模拟串口使用注意事项:

    1、两个模拟串口分布在不同PORT LINE,即一个用PORT2,一个用PORT3,不能用同一个PORT

    2、各自使用自己的定时器。

    3、每一个函数都要能立即退出,不要使其出现卡死现象。将每个函数想象成在一进就出、各不干扰、独立运行的状态执行。

    4、发送过程中产生接收,则以接收的优先级为高。

       增加发送自动退让,发送过程随时可能被接收中断,这样会导致发送的数据出现错误但接收的数据都是正常的。BUG.......................

       周立功串口写的很好在只使用一个定时器的情况下,做到了无一错发,无一漏收,可连续收发,波特率稳定可调,这才是正真的高手!!!

       增加接收数据计数,发送数据计数!

       增加当接收过程终止发送时拉高TX引脚操作!

       用串口调试助手测线序数据连续发送且能正常回显的最小时间,目前是300ms

       测试串:12 34 56 78 90 1A 3E 5B 12 34 56 78 90 1A 3E 5B

      

      

    5、对于连续接收情况的处理

       根据精确的停止位的后一位电平高低判断是否为连续接收的情况

       使用停止位判断,只能选择一位(k=0)或两位停止位(K=1

       没有校验位

       要求连续收发10个字节以上,不行的话调节BAUD系数

    6、一旦错过了起始位是否会一直出错!

    myiouart:

    特点

    1、支持一个定时器多通道引脚分时复用,通过channel选择。

         配置一个串口支持多个引脚发送,或接收通过channel变量选择哪一对引脚通道。

    3、测试模拟串口性能方法:

    使用回显测试:

    在secureCRT中: 按住两个按键不放看是否能正常显示,或同时按住多个看是否有乱码现象。当同时按住两个字符按键不放时,正常程序每次返回两个按下的字符,此时串口工作在连发状态下。

    在串口调试助手中:连续发送多个字节看返回值是否正确。

    4、Myiouart_Lpc11c14_V1程序DEBUG记录:

    V1.0 -- 只支持发送,接收波特率一高就有问题,4800接收

    V1.1 -- 修改了收发(只是单字节收发),跟换了32位定时器1,并将驱动单独列在一个文件中。

    V1.2 -- 增加了BUFFER功能

    V1.3 -- 增加了连续收发,但发送会被接收终止,导致发送的数据错误

    V1.4 --

    V1.5 -- 改为双定器模拟串口

    V1.6 -- 单定时器串口升级至V1.6使用了结构体操作方式

    参考:

    IO 模拟 UART 实现-ZLG

    链接:https://pan.baidu.com/s/1OgQshNoEe5oI0_g5cQPXHg 密码:0svc

    下载:

    V1.5

    链接:https://pan.baidu.com/s/11pwEpICOpuX6S5OYy6xUtg 密码:f5l9

    V1.6

    链接:https://pan.baidu.com/s/1UimbCwUY3uINvajBQ5d8HQ 密码:m044

    展开全文
  • 串口UART 时序 和数据传输

    千次阅读 2019-07-31 23:06:03
    UART是一种通用串行数据总线,用于异步通信。该总线双向通信,可以实现全双工传输和接收。 UART通信协议 UART作为异步串口通信协议的一种,工作原理是将传输数据的每个字符一位接一位地传输。其中每一位(Bit)的意义...



    UART(Universal Asynchronous Receiver / Transmitter:通用异步收发传输器)是一种通用串行数据总线,用于异步通信。
    该总线双向通信,可以实现全双工传输接收

    1、UART 通信协议

    UART作为异步串口 通信协议的一种,工作原理是将传输数据的每个字符1 bit 接 1 bit 地传输。
    其中每一位(it)的意义如下:

    序号bit 位描述
    1起始位先发出一个逻辑"0"的信号,表示传输字符的开始
    2数据位紧跟在起始位之后
    数据位的个数可以是 4、5、6、7、8 等,构成一个字符
    最低位开始传送,靠时钟定位
    3奇偶校验位数据位加上这一位后,使得"1"的位数应为偶数(偶校验)或奇数(奇校验),以此来校验数据传送的正确性
    4停止位一个字符数据的结束标志,可以是1位1.5位2位高电平
    5空闲位处于逻辑"1"的状态,表示当前线路上没有数据传送

    (1)UART协议传输时序(低位在前)如图所示:
    在这里插入图片描述
    (2)UART发送数据 “0x50 0x50”(0101 0000) 在示波器的图形显示:
    在这里插入图片描述

    2、UART 默认都是高电平

    TX,RX 引脚初始化完成,进入 等待通信状态(空闲状态),都是高电平。

    展开全文
  • 串口通讯协议的时序讲解

    万次阅读 2019-07-06 18:55:16
    串口通讯(Serial Communication)是一种非常常用的串行...我们常说的UART、RS232、RS422、RS485都是采用了这种通讯协议,其接口时序都是一致的,只是具体的物理层的电平的不同。 因此,无论是RS232协议,还是RS48...
  • UART串口协议时序

    千次阅读 2021-08-31 13:16:45
    为了在编写协议的时候更加方便,笔者使用逻辑分析仪读取了UART串口协议的时序,记录如下。 UART协议 波特率 起始位 数据位 奇偶校验位 停止位 1. 波特率9600,数据位8,无奇偶校验位,停止位1。 单字节情况: 多...
  • 串口UART时序和数据传输

    千次阅读 2020-04-02 11:20:30
    UART(Universal Asynchronous Receiver/Transmitter:通用异步收发传输器)是一种通用串行数据总线,用于异步通信。该总线双向通信,可以实现全双工传输和接收。 UART通信协议 UART作为异步串口通信协议的一种...
  • 串行通讯的时序分析

    千次阅读 2016-03-13 09:59:39
    通信协议按时间分为:同步通信 和异步通信,按发送数据的位宽可分为串行通信和并行通信,串行通信里按通信数据传输的方向机是否同时收发程序通信又分为:单工,半双工,全双工。 区别:同步和异步: 同步是面向...
  • 这篇文章主要总结一下串口通信的收发时序,IIC是一种半双工的通信协议,收发共用一条数据线,串口是一种全双工的通信协议,和IIC存在比较大的区别,所以就把串口也总结一下。
  • 随着FPGA技术的高速发展,一些常见的接口电路的时序电路可以通过FPGA实现,通过这种设计可减少电路系统元件的数量,提高系统集成度和可靠性。详细阐述了如何通过FPGA实现RS 232接口时序逻辑设计。  关键词:FPGA...
  • uart接口时序分析

    千次阅读 2020-04-17 02:05:56
    数据传送速率用波特率来表示, 指单位时间内... 传输时序如下图    在UART中,信号线上共有两种状态, 分别用逻辑1(高电平)和逻辑0(低电平)来区分  在空闲时, 数据线应该保持在逻辑高电平状态  其中...
  • 随着FPGA技术的高速发展,一些常见的接口电路的时序电路可以通过FPGA实现,通过这种设计可减少电路系统元件的数量,提高系统集成度和可靠性。详细阐述了如何通过FPGA实现RS 232接口时序逻辑设计。  关键词:FPGA...
  • 采用新塘处理器NUC972 使用该芯片所有的串口 UART1~UART10 测试发现串口数据读取异常 采用测试串口终端SSCOM 问题还原步骤 内核已经配置了所有的串口功能,串口PIN复用正常 设备启动可以识别10个串口 ~ # ls /dev/...
  • 11111
  • SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便,正是出于这种简单易用的特性,现在越来越多的芯片集成了这种通信协议。
  • SPI接口原理与时序

    2020-05-14 19:11:40
    SPI接口原理与时序 SPI是串行外设接口(Serial Peripheral Interface)的缩写,是一种高速的,全双工,同步的串行通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供...
  • SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,...SPI是一个环形总线结构,由ss(cs)、sck、sdi、sdo构成,其时序其实很简单,主要是在sck的控制下,两个双向移位寄存器进行数据交换。
  • 项目开发中遇到接收串口数据时序混乱的问题 刷卡模块出现响应很慢的情况,或者说时序不一样的情况,很可能是开了两个应用同时在给串口发送数据。出现这种情况的解决办法: 1:用TLL转USB链接刷卡器,循环给刷卡器...
  • 首先看UART发送时序图: 要发送一个完整字节,需要“1位起始位+8位数据位+1位停止位”,图上的第11位,是确认一个字节发送完的一位。 重点是每一位之间的发送时间需要保持一致,也就是bps_clk的每个高脉冲之间的...
  • 串口比较轴,先发低位: 参考人家I2C,就是先发高位:
  • 串口系统简图、时序

    千次阅读 2018-05-21 14:14:15
    串口系统简图串口线程时序
  • 什么是时序电路虽然每个数字电路系统可能包含有组合电路,但是在实际应用中绝大多数的系统还包括存储元件,我们将这样的系统描述为时序电路。时序电路,是由最基本的逻辑门电路加上反馈逻辑回路(输出到输入)或器件...
  • 经常遇到初学者,对单片机串行通讯出了问题不知道如何办的情况。其实最有效的调试方法是用示波器观察收发数据的波形。通过观察波形可以确定发送正确与否;
  • 2.3.2 UART传输时序分析 ...              图2 33 串口时序                       表2 7 串口时序说明表   在串口的总线上“高电平”是默认的状态,当一帧数据的开...
  • 1、UART(Universal Asynchronous Receiver Transmitter)总线是异步串口,故一般比I2C、SPI两种同步串口的结构要复杂很多,一般由波特率产生器(产生的波特率等于传输波特率的16倍)、UART接收器、UART发送器组成,硬件...
  • 基于STM32的12864串行时序的实现

    万次阅读 2015-07-21 22:47:04
    以下是12864液晶串行时序图,下面就根据这个图来分析一下12864串行时序的实现,只有真正弄清楚了时序图才能真正了解串行传输的原理。    从图上可以看出串行传输时需要用到CS,SCLK,SID三根信号线,但是...
  • 类 型:串行异步通信 总线定义: TXD:发送数据线 RXD:接收数据线 数据传输: ①接收方RX初始电平为1 ②带起始位0和停止位1 ③先发送低位再高位 ④传输数据位以字节为单位,一次只能传输一字节 ⑤以波特率为时基...
  • 数字音频接口时序简介

    千次阅读 2020-05-09 23:47:46
    最近在做音频这块,接触了挺多接口,收集了一下各种音频接口的介绍,包括: PCM、I2S、TDM、PDM,一般通用的就这四种。 1.PCM(脉冲编码调制) 接口定义都是一样的 分别是: 位时钟信号(BCLK),同步信号(LRCK),...
  • 摘 要:介绍了计算机异步串行接口键盘的特殊设计要求和工作原理,结合开发过程,讨论分析了89C51芯片的结构、功能特点以及应用中需要注意的问题,并给出了计算机串行接口键盘的硬件原理图及软件流程图。 关键词:...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 24,907
精华内容 9,962
关键字:

串口时序

友情链接: SQLitelizi.zip