2018-05-03 00:23:40 u011329967 阅读数 5002
  • 串口通信和RS485-第1季第13部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第13个课程,主要讲解了串行通信UART及其扩展RS485。本课程很重要,因为串口通信是我们接触的早也简单的通信方式,是后续继续学习SPI、I2C甚至USB、网络通信等的基础,大家务必认证对待完全掌握。

    6151 人正在学习 去看看 朱有鹏

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

2019-08-17 10:06:00 qq_19582165 阅读数 18
  • 串口通信和RS485-第1季第13部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第13个课程,主要讲解了串行通信UART及其扩展RS485。本课程很重要,因为串口通信是我们接触的早也简单的通信方式,是后续继续学习SPI、I2C甚至USB、网络通信等的基础,大家务必认证对待完全掌握。

    6151 人正在学习 去看看 朱有鹏

#include <reg52.h>
#include "main.h"
#include "smartcard.h"
#include "stdio.h"

typedef enum { false, true }bool;

#if 0
sbit PIN_RXD = P1^0; //接收发送同一个引脚定义
sbit PIN_TXD = P1^0; //接收发送同一个发送引脚定义
sbit PIN_CLK = P3^1; //智能卡时钟引脚定义
sbit PIN_3v5v = P3^2; //智能卡3v_5v引脚定义
sbit PIN_RST = P3^3; //智能卡复位引脚定义
sbit PIN_CMDVCC = P3^4; //智能卡CMD引脚定义
#else
// test Parity
sbit PIN_RXD = P1^0; //接收 脚定义
sbit PIN_TXD = P1^2; //发送 脚定义
sbit PIN_CLK = P3^5; //智能卡时钟引脚定义
sbit PIN_3v5v = P3^2; //智能卡3v_5v引脚定义
sbit PIN_RST = P3^3; //智能卡复位引脚定义
sbit PIN_CMDVCC = P3^4; //智能卡CMD引脚定义

sbit Test_CLK = P0^3; //接收 脚定义

 

#endif

bit RxdOrTxd = 0; //指示当前状态为接收还是发送
bit RxdEnd = 0; //接收结束标志
bit TxdEnd = 0; //发送结束标志
uint8_t RxdBuf = 0; //接收缓冲器
uint8_t TxdBuf = 0; //发送缓冲器
void ConfigUART(unsigned int baud);
void StartTXD(unsigned char dat);
void StartRXD();
void test_IO();

//通过嵌套宏定义,制作一张包括0~255各个数字中包含1的个数,其中包含偶数个1,则ParityTable256[i]=0,否则ParityTable256[i]=1;


static const bool ParityTable256[256] =
{
#define P2(n) n, n^1, n^1, n
#define P4(n) P2(n), P2(n^1), P2(n^1), P2(n)
#define P6(n) P4(n), P4(n^1), P4(n^1), P4(n)
P6(0), P6(1), P6(1), P6(0)
};


void mainb(){
EA = 1; //开总中断
ConfigUART(9600);//配置波特率为 9600
while (1){
while (PIN_RXD); //等待接收引脚出现低电平,即起始位
StartRXD(); //启动接收
while (!RxdEnd); //等待接收完成
StartTXD(RxdBuf+1); //接收到的数据+1 后,发送回去
while (!TxdEnd); //等待发送完成
}
return;
}

void SET_3v5v()
{
PIN_3v5v=1;
}
void RESET_3v5v()
{
PIN_3v5v=0;
}

void RST_SET(BitAction ResetState)
{

PIN_RST = ResetState;
}

void SET_CMVCC()
{
PIN_CMDVCC =1;
}
void RESET_CMVCC()
{
PIN_CMDVCC =0;
}

/* 串口配置函数,baud-通信波特率 */
void ConfigUART(unsigned int baud){
TMOD &= 0xF0; //清零 T0 的控制位
TMOD |= 0x02; //配置 T0 为模式 2
// TH0 = 256 - (11059200/6)/baud; //计算 T0 重载值
TH0 = 256 - (FOSC/12)/baud; //计算 T0 重载值

}
/* 启动串行接收 */
void StartRXD(){


while (PIN_RXD);
//printf("PIN_RXD2=0x%02X\r\n", (int)PIN_RXD);
TL0 = 256 - ((256-TH0)>>1); //接收启动时的 T0 定时为半个波特率周期
ET0 = 1; //使能 T0 中断
TR0 = 1; //启动 T0
RxdEnd = 0; //清零接收结束标志
RxdOrTxd = 0; //设置当前状态为接收

}
/* 启动串行发送,dat-待发送字节数据 */
void StartTXD(uint8_t dat){
TxdBuf = dat; //待发送数据保存到发送缓冲器
TL0 = TH0; //T0 计数初值为重载值
ET0 = 1; //使能 T0 中断
TR0 = 1; //启动 T0
PIN_TXD = 0; //发送起始位
TxdEnd = 0; //清零发送结束标志
RxdOrTxd = 1; //设置当前状态为发送
}

uint16_t USART_ReceiveData(USART_TypeDef* USARTx)
{
/* Check the parameters */
// assert_param(IS_USART_ALL_PERIPH(USARTx));

/* Receive Data */
#if 0
uint16_t tt= USARTx->SR ;
USARTx->SR = tt & (uint16_t)0x3df; //wuhh add ,remove later

return (uint16_t)(USARTx->DR & (uint16_t)0x01FF);
#endif
return (uint16_t) RxdBuf;

}
void USART_SendData(USART_TypeDef* USARTx, uint8_t Data)
{
StartTXD(Data);
}
FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG)
{
FlagStatus bitstatus = RESET;
if (USART_FLAG== USART_FLAG_TC)
if (TxdEnd)
{
bitstatus = SET;
}
else
{
bitstatus = RESET;
}

if (USART_FLAG== USART_FLAG_RXNE)
if (RxdEnd)
{
bitstatus = SET;
}
else
{
bitstatus = RESET;
}
return bitstatus;
}
static bit polarity = 0; //输出智能卡时钟极性

#if 1

/* T0 中断服务函数,处理串行发送和接收 */
void InterruptTimer0() interrupt 1{

static unsigned char cnt = 0; //位接收或发送计数
Test_CLK = !Test_CLK;

if (RxdOrTxd)
{ //串行发送处理
cnt++;
if (cnt <= 8){ //低位在先依次发送 8bit 数据位
PIN_TXD = TxdBuf & 0x01;
TxdBuf >>= 1;
}else
if (cnt == 9)
{ //发送停止位
PIN_TXD = 1;
}
else{ //发送结束
cnt = 0; //复位 bit 计数器
TR0 = 0; //关闭 T0
TxdEnd = 1; //置发送结束标志
}
}
else{ //串行接收处理
if (cnt == 0){ //处理起始位
if (!PIN_RXD){ //起始位为 0 时,清零接收缓冲器,准备接收数据位
RxdBuf = 0;
cnt++;
}
else{ //起始位不为 0 时,中止接收
TR0 = 0; //关闭 T0
}
}else if (cnt <= 8){ //处理 8 位数据位
RxdBuf >>= 1; //低位在先,所以将之前接收的位向右移
//接收脚为 1 时,缓冲器最高位置 1,
//而为 0 时不处理即仍保持移位后的 0
if (PIN_RXD){
RxdBuf |= 0x80;
}
cnt++;
}else{ //停止位处理
cnt = 0; //复位 bit 计数器
TR0 = 0; //关闭 T0
if (PIN_RXD){ //停止位为 1 时,方能认为数据有效
RxdEnd = 1; //置接收结束标志
}
}
}
}

#else
/* T0 中断服务函数,处理串行发送和接收 */

void InterruptTimer0() interrupt 1{

static unsigned char cnt = 0; //位接收或发送计数
//test_IO();
#if 0
PIN_TXD = !PIN_TXD;
#else

if (RxdOrTxd){ //串行发送处理
cnt++;
if (cnt <= 8){ //低位在先依次发送 8bit 数据位
PIN_TXD = TxdBuf & 0x01;
TxdBuf >>= 1;
}else if (cnt == 9){ //奇偶位
PIN_TXD=ParityTable256[TxdBuf];
}else if (cnt == 10){ //发送停止位1 智能卡协议共两个停止位
PIN_TXD = 1;
}else if (cnt == 11){ //发送停止位2
PIN_TXD = 1;
}else{ //发送结束
cnt = 0; //复位 bit 计数器
TR0 = 0; //关闭 T0
TxdEnd = 1; //置发送结束标志
}
}else{ //串行接收处理
if (cnt == 0){ //处理起始位
if (!PIN_RXD){ //起始位为 0 时,清零接收缓冲器,准备接收数据位
RxdBuf = 0;
cnt++;
//printf("InterruptTimer 0\n");
} else{ //起始位不为 0 时,中止接收
TR0 = 0; //关闭 T0
printf("InterruptTimer close\n");
}
}
else if (cnt <= 8){ //处理 8 位数据位
RxdBuf >>= 1; //低位在先,所以将之前接收的位向右移
//接收脚为 1 时,缓冲器最高位置 1,
//而为 0 时不处理即仍保持移位后的 0
if (PIN_RXD){
RxdBuf |= 0x80;
}
printf("RxdBuf=0x%02X\r\n", (int)RxdBuf);
cnt++;
}else{ //停止位处理
cnt = 0; //复位 bit 计数器
TR0 = 0; //关闭 T0
if (PIN_RXD){ //停止位为 1 时,方能认为数据有效
RxdEnd = 1; //置接收结束标志
}
}
}
#endif
}
#endif

2013-04-23 10:25:05 firstblood2008 阅读数 693
  • 串口通信和RS485-第1季第13部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第13个课程,主要讲解了串行通信UART及其扩展RS485。本课程很重要,因为串口通信是我们接触的早也简单的通信方式,是后续继续学习SPI、I2C甚至USB、网络通信等的基础,大家务必认证对待完全掌握。

    6151 人正在学习 去看看 朱有鹏

从GIS软件工程转到嵌入式开发有一年了,总结嵌入式开发的一些小技巧。

本例模拟发送8位数据,其它位数视情况调整,本程序在VS2008下调试通过。

#include <stdio.h>
#include <stdlib.h>

typedef unsigned char byte;

int i = 0;            // 传入的位数
byte value = 0;       // 接收uart数据

/*
*@brief 模拟bit型数据,
*/
typedef struct BIT_st
{
    byte data:1;
}bit;

/*
*@brief 
*
*移植入单片机时可将参数改为串口数据寄存器变量
*@param bit bit_data -- 按位发送的数据
*@retval byte -- 返回接受的数据
*/
byte receive_bit(bit bit_data)
{
    /* 接受8位数据 */
    if (i==8)
    {
        i=0;
        return value;
    }

    /* 按位接收数据主代码 */
    if (bit_data.data)
    {
      value |= (1<<i);
    }
    else
    {
      value &= ~(1<<i);
    }

    i++;
    return value;
}

int main()
{
    int j = 0;
    bit uart_data[8] = {1,0,1,0,1,0,1,0};    // uart_data = 85;
    byte ret = 0;

    for (j=0; j<8; j++)
    {
        ret = receive_bit(uart_data[j]);
    }

    printf("%d\n", ret);
    return 0;
}

搞了几年的技术,刚有写博客的觉悟,不足之处还请指教。




2017-06-27 14:57:35 u013082827 阅读数 934
  • 串口通信和RS485-第1季第13部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第13个课程,主要讲解了串行通信UART及其扩展RS485。本课程很重要,因为串口通信是我们接触的早也简单的通信方式,是后续继续学习SPI、I2C甚至USB、网络通信等的基础,大家务必认证对待完全掌握。

    6151 人正在学习 去看看 朱有鹏

UART、RS-232、RS-422、RS-485有什么区别?

  • 文章来源

        我最近用单片机,通信方式一直是UART方式,后来说通信协议是RS-422,我一头雾水:我只会用读写SBUF进行单片机和计算机串口通信,更改之后,我的单片机程序要做变更吗?难道还要我像模拟IIC那样,自己按照逐个bit发送接收数据进行通信?这样的话要花不少时间呢。
        于是我查了一下UART和RS系列通信的关系,发现我的担忧是多余的,而且,显得很不专业。写这篇文章之后,相信就能把他们之间的关系彻底搞清楚了。
    
  • 串口通信协议

        这里按照通信的流程介绍。首先有一个固定的串口通信协议,只要通信双方规定好通信的帧格式(8位还是10位、要不要奇偶校验等)和速率(波特率)等参数,就可以进行通信,具体起始位、数据位、奇偶校验位等实现,是由硬件来实现的,这里的硬件就是UART,硬件实现的意思就是,UART接收到输入数据,按照串口通信协议转化成TTL电平发送给到TX/RX线路上。总的通信流程就是:
    处理器并行数据——输入到——遵循串口通信协议的UART——对外输出——TX/RX两条线上的TTL电平——TTL转232/485/422芯片(比如MAX232)——外部器件的串口接收——先把RS电平转化成接收数据——按照上面的串口通信协议解调数据——使用
    
  • UART是硬件

        UART是通用异步收发传输器(Universal Asynchronous Receiver/Transmitter),通常称作UART,是一种异步收发传输器。这里注意,UART虽然有固定的通信协议,但它指的是一个硬件,是把处理器内部并行数据转化为串行数据的硬件设备。一边是处理器的数据,一边是外接串行设备的数据。以C8051F系类的处理器为例如图:
    

    每个MCU都有对外UART接口,而且一般还不止一个

  • 谁是电平标准,谁是通信协议?

        UART按照串口通信协议,将数据转化为RX/TX上“高低”电平的形式对外输出(或接收),这里的高低电平,采用的是TTL的标准:
    TTL:Transistor-Transistor Logic 三极管逻辑。 
    Vcc:5V; 
    VIH>=2V;VIL<=0.8V。 
        有些设备的接口,采用的也是这种串行通信协议,但采用的电平标准和TTL不同,如RS-232、RS-485、RS-422。对,RS-系列都是电平标准的意思。也即是说,RS-系列和TTL对高低电平的定义不一样:
    

    RS-232电平标准
    RS-485.422
    到这里已经很清楚了,UART不是通信协议,是遵循串行通信协议、输出TTL电平的硬件;RS-系列也只是电平标准,解调时需要先按照这种标准进行高低电平判断,再对高低电平按照串口通信协议进行解调。

  • 回到问题

    回到我们的问题:原来我用UART,现在强调422标准,我需要做什么?应该是什么也不用管。原来我使用开发板,C8051FX通过UART0往计算机发数据,开发板上有一个UART_TTL转RS-232的芯片MAX232,RS-232对应的硬件是9帧串口,再转USB,流程为:
    UART——MAX3232——RS232串口——串口转USB——计算机接收
    

    MAX3232
    现在换了RS-422标准,只是在硬件上把MAX3232换成MAX488(或者其他芯片),并不会影响到我的UART发送TX/RX数据,单片机程序也不用调整了。实际上,UART的工作原理也不需要了解,我只知道往SBUF寄存器读写数据,可以在某个TX/RX输出或接收TTL电平就可以了。

  • 最后

        经过陆陆续续一下午时间的总结,以后我对这类问题应该有一个更加清晰的认识了。
    
2012-07-26 16:31:14 sy_lixiang 阅读数 5348
  • 串口通信和RS485-第1季第13部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第13个课程,主要讲解了串行通信UART及其扩展RS485。本课程很重要,因为串口通信是我们接触的早也简单的通信方式,是后续继续学习SPI、I2C甚至USB、网络通信等的基础,大家务必认证对待完全掌握。

    6151 人正在学习 去看看 朱有鹏

近日因工作关系,需要用STM8L101F3P6这款单片机用IO口模拟串行通讯,波特率2400bps,前辈同事已经写完了程序,我需要拿来研究一下该款MCU的低功耗的情况,而在调试的过程中,发现1个奇怪的问题,描述如下:

在while(1){}的循环中,无论是接收还是发送。第一次循环的收发数据都是错的,此后的循环均正确。比如:PC一个字符一个字符的发送0x01,0x02,0x03,接收到3个字符MCU就发回来,但第1次循环接收到是错误数据0x40,0xA0,0xE0,此后再循环收发均正确。。。百思不得其解,在while(1)循环内还会出这种问题?

代码如下:

/**********************************************
描述:用延时法模拟串口通讯,中断方式接收

硬件:2MHz,内部默认16Mhz,8分频,STM8L101F3P6,RXD---PB7.TXD---PB4
波特率:2400

测试:上电后,分别发送0x01,0x02,0x03,3个字符。
问题:第1次循环接收到的字符不正确,但第2次以后均正确

时间:2012.07.26 于单位
**********************************************/
#include "stm8l10x.h"
#include "stm8l10x_clk.h"
#include "stm8l10x_gpio.h"

#define RXD_IN  (GPIO_Pin_7)					//RXD
#define TXD_OUT (GPIO_Pin_4)					//TXD

unsigned char ReadBuf[64];						//接收缓冲

void CLK_Init(void)
{
	CLK_DeInit();
	CLK_MasterPrescalerConfig(CLK_MasterPrescaler_HSIDiv8);
}

void IOInit(void)
{	
	GPIO_Init(GPIOA, GPIO_Pin_0 | GPIO_Pin_2 | GPIO_Pin_3, GPIO_Mode_Out_PP_Low_Slow );	
	
	GPIO_Init(GPIOB, GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7 , GPIO_Mode_Out_PP_Low_Slow );	
	
	//2012.07.26 添加
	//造成问题的原因在于此,添加下面的语句可解决问题
	//串行通讯的起始位为低电平,上电之后TXD,RXD都应置为高电平
	//GPIO_Init(GPIOB, TXD_OUT, GPIO_Mode_Out_PP_High_Slow);
	
	GPIO_Init(GPIOB, RXD_IN, GPIO_Mode_In_PU_IT);	

	GPIO_Init(GPIOC, GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 , GPIO_Mode_Out_PP_Low_Slow );
	
	GPIO_Init(GPIOD, GPIO_Pin_0, GPIO_Mode_Out_PP_Low_Slow );
}

void Delay_us(unsigned int nCount) 
{ 
	for (; nCount != 0; nCount--);
}

void Delay(u16 nCount)
{
	while (nCount != 0)
	{
		nCount--;
	}
}

void Delay_ms(void)
{
	int i=0;
	for (i=0; i<397; i++);	
}

void SEND_1(void)
{
	GPIOB->ODR |=0x10;  //PB4=1,TXD 
}

void SEND_0(void)
{
	GPIOB->ODR &=0xEF;  //PB4=0,TXD
}

void WriteByte(unsigned char sdata)
{
	unsigned char i;
	unsigned char value=0;

	//发送起始位
	SEND_0();
	Delay_us(100);//45
	
	//发送数据位
	for(i=0;i<8;i++)
	{
		value=(sdata&0x01);      //先传低位
		if(value) 
		{
			SEND_1();
		}
		else {
			SEND_0();
		}  
		Delay_us(88);//40
		sdata=sdata>>1;
	}

	//停止位
	SEND_1();
	Delay_us(100);	//50
}

unsigned char ReadByte(void)	
{
	unsigned char i,value=0;

	while(1)
	{
		if(!(GPIO_ReadInputData(GPIOB)&0x80))
		{
			//等过起始位
			Delay_us(100);
			
			//接收8位数据位
			for(i=0;i<8;i++)
			{
				value>>=1;	
				if((GPIO_ReadInputData(GPIOB)&0x80))
				{
					value|=0x80;
				}
				Delay_us(90);
			}
			
			Delay_us(50);
			
			return value;
		}
	}
}

unsigned char ReadAndWrite(unsigned char *RBuf)
{
	GPIO_Init(GPIOB, RXD_IN, GPIO_Mode_In_PU_No_IT); // RXD

	RBuf[0]=ReadByte();
	RBuf[1]=ReadByte();
	RBuf[2]=ReadByte();	

	WriteByte(RBuf[0]);
	WriteByte(RBuf[1]);
	WriteByte(RBuf[2]);
					
	return 1;
}

void main(void)
{
	unsigned char ccc;

	CLK_Init();
	IOInit();

	EXTI_SetPinSensitivity(EXTI_Pin_7, EXTI_Trigger_Rising_Falling);			
	enableInterrupts();	

	while(1)
	{	
		ccc=ReadAndWrite(ReadBuf);
	}	
}

 

病症如下:


-----------------------------------------------------------------------------------------------------------------------------------

上电后:

此时已经能看出问题了,想想看。

-----------------------------------------------------------------------------------------------------------------------------------

发送0x01:

-----------------------------------------------------------------------------------------------------------------------------------

发送0x02:

-----------------------------------------------------------------------------------------------------------------------------------

发送0x03:

-----------------------------------------------------------------------------------------------------------------------------------

症状:

 

-----------------------------------------------------------------------------------------------------------------------------------

再发0x01:

-----------------------------------------------------------------------------------------------------------------------------------

再发0x02:

-----------------------------------------------------------------------------------------------------------------------------------

再发0x03:

看到这,我想应该知道问题出现在哪了吧?哈哈。

-----------------------------------------------------------------------------------------------------------------------------------

分析:

用IO口模拟串行通讯,串口通讯的起始位用低电平0表示,停止位用高电平1来表示。在没有进行数据收发的时候,要使TXD保持高电平,以便能识别出特发数据的起始位。解决办法是,上电初始化时,使TXD引脚为高电平。

-----------------------------------------------------------------------------------------------------------------------------------

病好了:

没有更多推荐了,返回首页