Linux串列埠程式收發16進位制資料錯誤

詆調發表於2014-09-26

問題描述:

在linux下面通過通過C實現串列埠程式網zigbee中寫入16進位制數,但是zigbee執行總是接受不到資料,然後通過IAR檢視MT_UartProcessZToolData()函式中接收到的資料,發現當我傳送0x01時,zigbee接收到的資料為0x81,傳送0xfe時,zigbee接收到也是0xfe,但是寫寫回串列埠,linux接收到的是0x7f 。資料的最高位出現了問題,然後再x86中使用串列埠除錯工具並未出現這樣的狀況,所以鎖定我linux中串列埠程式有問題。最後是c_iflag設定錯誤

/*
*Uart.c
*串列埠初始化
*/

#include "Uart.h"
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>
#include <stdlib.h>
#include<linux/types.h>
#include<sys/time.h>

/*
	巨集定義
*/
#ifdef DEBUG
	#define A_OUT printf("%s:%s:%d:", __FILE__, __FUNCTION__,__LINE__);fflush(stdout);
	#define Printf(fmt, arg...) A_OUT printf(fmt, ##arg)
#else
	#define A_OUT
	#define Printf(fmt, arg...)
#endif

/*
	全域性變數
*/
int SerialFd;//儲存串列埠檔案描述符


/*
******************************************************************************************
** 函式名稱 : int HW_Uart_Config (int nSpeed, int nBits, char nEvent, int nStop) 
** 函式功能 : 設定串列埠引數                        
** 入口引數 : 
**			   nSpeed:波特率
**			   nBits:資料位
**			   nEvent:奇偶校驗位
**			   nStop:停止位			   
** 出口引數 : -1 設定失敗
**				0 設定成功
** 函式說明 : 設定串列埠詳細引數
******************************************************************************************
*/
int HW_Uart_Config (int nSpeed, int nBits, char nEvent, int nStop) 
{ 
	struct termios newtio, oldtio; 
	/*tcgetattr(SerialFd,&options)得到與SerialFd指向物件的相關引數,
	並將它們儲存於oldtio,該函式,還可以測試配置是否正確,該串列埠是否
	可用等。若呼叫成功,函式返回值為0,若呼叫失敗,函式返回值為1.*/
	if (tcgetattr (SerialFd, &oldtio) != 0)
    {      
		perror ("SetupSerial 1");      
		return -1;   
	}
  
	bzero (&newtio, sizeof (newtio)); 
	//CLOCAL:修改控制模式,保證程式不會佔用串列埠
	//CREAD:修改控制模式,使得能夠從串列埠中讀取輸入資料
	newtio.c_cflag |= CLOCAL | CREAD; 
	
	//設定資料位
	newtio.c_cflag &= ~CSIZE; //遮蔽其他標誌位
	switch (nBits)   
    {  
	case 7:   
		newtio.c_cflag |= CS7;   
		break;  
	case 8:   
		newtio.c_cflag |= CS8;   
		break; 
	}
	
	//設定奇偶校驗
	switch (nEvent)   
    {
	case 'o':
	case 'O':   //設定為奇校驗   
		newtio.c_cflag |= PARENB;    
		newtio.c_cflag |= PARODD;    
		newtio.c_iflag |= (INPCK | ISTRIP);    
	break;  
	case 'e':
	case 'E':    //設定為偶校驗
		newtio.c_iflag |= (INPCK | ISTRIP);			  
		newtio.c_cflag |= PARENB;			  
		newtio.c_cflag &= ~PARODD;			  
		break;  
	case 'n':	//無奇偶校驗位。	
	case 'N':      
		newtio.c_iflag &= ~INPCK ;//導致資料收發錯誤是由於這裡設定錯誤, 將c_iflag看出C_cflag	
		newtio.c_cflag &= ~PARENB;		
	//	newtio.c_cflag &= ~INPCK;//導致收發資料錯誤
		break; 
	case 'S':  
	case 's':           /*as no parity */  
		newtio.c_cflag &= ~PARENB;  
		newtio.c_cflag &= ~CSTOPB;  
	break;  		
	default :
		return -1;
	}
  
	//設定串列埠輸入波特率和輸出波特率
	switch (nSpeed)    
    {    
	case 2400:      
		cfsetispeed (&newtio, B2400);			  
		cfsetospeed (&newtio, B2400);			  
		break;    
	case 4800:      
		cfsetispeed (&newtio, B4800);			  
		cfsetospeed (&newtio, B4800);			  
		break;   
	case 9600:     
		cfsetispeed (&newtio, B9600);			  
		cfsetospeed (&newtio, B9600);			  
		break;   
	case 115200:      
		cfsetispeed (&newtio, B115200);
		cfsetospeed (&newtio, B115200);	  
		break;  
	case 460800:   
		cfsetispeed (&newtio, B460800);			  
		cfsetospeed (&newtio, B460800);			  
		break;    
	default:     
		return -1;  
	}
      // 設定停止位 
	switch(nStop)
	{
		case 1:
			newtio.c_cflag &= ~CSTOPB; 
		break;
		case 2:
			newtio.c_cflag |= CSTOPB; 
		break;
		default:
			return -1;
	}
	
	//設定等待時間和最小接收字元
	newtio.c_cc[VTIME] = 0;	//讀取一個字元等待1*(1/10)s 
	newtio.c_cc[VMIN] = 0;	//讀取字元的最少個數
	//如果不是開發終端之類的,只是串列埠傳輸資料,
	//而不需要串列埠來處理,那麼使用原始模式(Raw Mode)方式來通訊
	newtio.c_lflag  &= ~(ICANON | ECHO | ECHOE | ISIG);  /*Input*/
	newtio.c_oflag  &= ~OPOST;   /*Output*/
	
	//如果發生資料溢位,接收資料,但是不再讀取
	tcflush (SerialFd, TCIFLUSH);
	//啟用配置 (將修改後的termios資料設定到串列埠中)
	if ((tcsetattr (SerialFd, TCSANOW, &newtio)) != 0)   
    {     
		perror ("com set error");			  
		return -1;
	} 
	Printf("set done!\n"); 
	return 0;
}

/*
******************************************************************************************
** 函式名稱 : int HW_Uart_Open (const char* DevicePath)  
** 函式功能 : 開啟串列埠裝置                          
** 入口引數 : DevicePath: 開啟串列埠的絕對路徑
** 出口引數 : -1 開啟失敗
**				 開啟成功 返回描述符
** 函式說明 : 以非阻塞的方式開啟串列埠裝置
******************************************************************************************
*/
int HW_Uart_Open (const char* DevicePath) 
{
	
		SerialFd = open( DevicePath, O_RDWR | O_NOCTTY | O_NDELAY );      
		if (-1 == SerialFd)
		{	  
			perror ("Can't Open Serial Port /dev/ttySAC0");				  
			return (-1);	
		} 
		
#if 0
    if ( fcntl (SerialFd, F_SETFL, 0) < 0 )  
		Printf ("fcntl failed!\n");
	else 
		Printf ("fcntl=%d\n", fcntl (SerialFd, F_SETFL, 0));
	if ( 0 == isatty (STDIN_FILENO) ) 
		Printf ("standard input is not a terminal device\n");
	else
		Printf ("isatty success!\n");	  
	Printf ("SerialFd-open=%d\n", SerialFd);
  
#endif	
    return SerialFd;
}

/*
******************************************************************************************
** 函式名稱 : int HW_Uart_Close (int SerialFd) 
** 函式功能 : 關閉串列埠裝置                          
** 入口引數 : SerialFd: 檔案描述符
** 出口引數 : void
** 函式說明 : 無
******************************************************************************************
*/

void HW_Uart_Close(int SerialFd)
{
	close(SerialFd);
}




相關文章