嵌入式开发板串口收发程序测试

使用的是飞凌嵌入式开发板OKMX6UL-C为底板的嵌入式开发板,测试效果串口助手向开发板发送内容打印在终端,需要注意的是,交叉编译使用与开发板相对于的交叉编译工具,采用arm-XXX-linux-gcc.核心板为FETMX6UL-C,如图:
在这里插入图片描述
头文件及其相关定义:

#include <termios.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <signal.h>

#define msleep(n) usleep(n*1000)   //延时1ms
/*定义全局变量*/
char first_test[200]="The first test loop\r\n";
volatile	int fd;                //volatile防止被优化
char* dev   = NULL;                //创建线程指针,串口名称串口三为:/dev/ttymxc2

pthread_mutex_t mut;               //线程锁保证所有线程对数据的修改是一致的
fd_set rd;                         //fd_set的数据结构,实际上是一long类型的数组

int nread,retval;                  //读操作和返回值
unsigned char msg[14];             //消息数组
char msg1[200];
int receiving_bit = 0;			   //消息接收标志位
struct timeval timeout={0,100};    //超时时间结构体

volatile	pthread_t thread[2];           //声明线程ID
volatile	const int READ_THREAD_ID = 0;  //读线程ID
volatile	const int SEND_THREAD_ID = 1;  //发送线程ID
volatile	int COM_READ_STATU = 1;  
volatile	int COM_SEND_STATU = 1; 
volatile	int sendnum=0,sendnum_times=0,recenum=0,recenum_times=0,cornum=0,cornum_times=0;

主函数调用相关函数:

/*定义主函数调用的函数*/
void read_port(void);              //监视端口情况读写或异常
void SignHandler(int iSignNo);     //终端信号监督
int OpenDev(char *Dev);            //打开配置相关串口驱动
static speed_t getBaudrate(int baudrate);  //波特率相关配置列表
int start_thread_func(void*(*func)(void*), pthread_t* pthread, void* par, int* COM_STATU);//创建线程
void* com_read(void* pstatu);      //读取端口线程锁控制
void* com_send(void* p);           //向端口发送loop内容
//void convertUnCharToStr(char* str, unsigned char* UnChar, int ucLen);  //unsigned char数组转化为char数组

首先看主函数:

/*主函数*/
int main(int argc, char **argv)
{
	//char *dev ="/dev/ttymxc1"; 
	signal(SIGINT,SignHandler);   //信号是进程在运行过程中,由自身产生或由进程外部发过来的事件
	dev   = argv[1];              //指针的指针,指向运行时的参数一
    if(dev==NULL)
	{
     	printf("Please input serial device name ,for exmaple /dev/ttymxc2.\n");
     	exit(1);
    }
	fd = OpenDev(dev);           //打开驱动相关配置
	if (fd>0)
	{}
	else
	{
		printf("Can't Open Serial Port %s \n",dev);
		exit(0);
	}	
	printf("\nWelcome to TTYtest! Press Ctrl + 'c' to stop.\n\n");
    pthread_mutex_init(&mut,NULL);        //用默认属性初始化互斥锁
	if(start_thread_func(com_read, (pthread_t*)&thread[READ_THREAD_ID],  (int *)&COM_READ_STATU, (int *)&COM_READ_STATU) != 0)  
    {  
        printf("error to leave\n");  
        return -1;  
    }  
  
	if(start_thread_func(com_send, (pthread_t*)&thread[SEND_THREAD_ID], (int *)&COM_SEND_STATU, (int *)&COM_SEND_STATU) != 0)
    {  
        printf("error to leave\n");  
        return -1;  
    }  
  	while(1)
  	{}   //根据具体情况决定在主函数中需要处理的事件
}

监视端口情况读写或异常:

void read_port(void)        //监视端口情况读写或异常
{   
    FD_ZERO(&rd);           //将rd清零使集合中不含任何fd
    FD_SET(fd,&rd);         //将fd加入rd集合

    retval = select (fd+1,&rd,NULL,NULL,&timeout); //监视我们需要监视的内容描述符的变化情况
    switch (retval)
    {
        case 0:
            // printf("no data input within  1s.\n");
            break;
        case -1:
            perror("select");
            break;       
        default:
			if((nread=read(fd,msg,1))>0)
			{
				receiving_bit = 1;
				printf("%s",msg);
				if(recenum<65535)
				{
					recenum++;
				}
				else
				{
					recenum_times++;
					recenum=1;
				}
			}
			break;
    }
}

终端信号处理:

void SignHandler(int iSignNo)   //终端信号监督
{
	int tmp_t=0;
	
	COM_SEND_STATU = 0; 
	msleep(1000);
	COM_READ_STATU = 0;         
	msleep(1000);

	//printf("%s,stop send,sendnum=%d,receivenum=%d\n",dev,sendnum*32,recenum);
	while(tmp_t<50000)
  	{
    	read_port();
		tmp_t++;
    }
	printf("\n%s,Send: %d ,Receive: %d \n",dev,(sendnum_times*65535+sendnum)*32,(recenum_times*65535+recenum));
	exit(1);	
}

波特率处理,下面列出两中方式,本文采用第二种
方式一:

int speed_arr[] = {B115200, B38400, B19200, B9600, B4800, B2400, B1200, B300, };  
int name_arr[] = {115200, 38400, 19200, 9600, 4800, 2400, 1200, 300, };  

void set_speed (int fd, int speed)  
{  
  int i;  
  int status;  
  struct termios Opt;  
  tcgetattr (fd, &Opt);  
  for (i = 0; i < sizeof (speed_arr) / sizeof (int); i++)  
    {  
		if (speed == name_arr[i])  
		{  
			tcflush (fd, TCIOFLUSH);  
			cfsetispeed (&Opt, speed_arr[i]);  
			cfsetospeed (&Opt, speed_arr[i]);  
			status = tcsetattr (fd, TCSANOW, &Opt);  
			if (status != 0)  
			{  
				perror ("tcsetattr fd1");  
				return;  
			}  
			tcflush (fd, TCIOFLUSH);  
		}  
    }  
}  

主函数中调用:set_speed (fd, 115200); 


方式二:

static speed_t getBaudrate(int baudrate)    //波特率相关配置列表
{
	switch(baudrate) {
	case 0: return B0;
	case 50: return B50;
	case 75: return B75;
	case 110: return B110;
	case 134: return B134;
	case 150: return B150;
	case 200: return B200;
	case 300: return B300;
	case 600: return B600;
	case 1200: return B1200;
	case 1800: return B1800;
	case 2400: return B2400;
	case 4800: return B4800;
	case 9600: return B9600;
	case 19200: return B19200;
	case 38400: return B38400;
	case 57600: return B57600;
	case 115200: return B115200;
	case 230400: return B230400;
	case 460800: return B460800;
	case 500000: return B500000;
	case 576000: return B576000;
	case 921600: return B921600;
	case 1000000: return B1000000;
	case 1152000: return B1152000;
	case 1500000: return B1500000;
	case 2000000: return B2000000;
	case 2500000: return B2500000;
	case 3000000: return B3000000;
	case 3500000: return B3500000;
	case 4000000: return B4000000;
	default: return -1;
	}
}

配置相关串口参数驱动是本文重点

int OpenDev(char *Dev)            //打开配置相关串口参数驱动
{
	speed_t speed;

    int i=0;
    int fdt,c=0,num;
    struct termios oldtio,newtio;

    speed = getBaudrate(9600);   //波特率相关配置speed = B9600;
    fdt=open(Dev,O_RDWR | O_NONBLOCK| O_NOCTTY | O_NDELAY); 
	//O_RDWR:一可读可写方式打开
	//O_NONBLOCK:使I/O变成非阻塞模式,它在读取不到数据时会回传-1,并且设置errno为EAGAIN
	//O_NOCTTY:如果文件为终端,那么终端不可以调用open系统调用的那个进程的控制终端
	//O_NDELAY:使I/O变成非阻塞模式,它在读取不到数据时会回传0
    if(fdt<0)
    {
        perror(Dev);
        exit(1);
    }
    //save to oldtio
    tcgetattr(fdt,&oldtio);        //使用函数tcgetattr保存原串口属性 
    //clear newtio
    bzero(&newtio,sizeof(newtio)); //清空newtio中相应位
    //newtio.c_cflag = speed|CS8|CLOCAL|CREAD|CRTSCTS;
    newtio.c_cflag = speed|CS8|CLOCAL|CREAD;// 控制模式标志:波特率|8个数据位|本地连接(不改变端口所有者)|接收使能
    newtio.c_iflag = IGNPAR;       //输入模式标志:忽略奇偶校验错误
    newtio.c_oflag = 0;            //输出模式标志:Raw 模式输出
    //printf("newtio.c_cflag=%x\n",newtio.c_cflag);
    tcflush(fdt,TCIFLUSH);         //丢弃要写入引用的对象,TCIFLUSH刷新收到的数据但是不读
    tcsetattr(fdt,TCSANOW,&newtio);       //设置与终端相关的参数,TCSANOW改变立即发生
    tcgetattr(fdt,&oldtio);        //得到与 fd 指向的对象相关的参数保存于结构中,函数可以从后台进程中调用;但是,终端属性可能被后来的前台进程所改变
    //printf("oldtio.c_cflag=%x\n",oldtio.c_cflag);
    return fdt;
}

线程处理相关内容:

void* com_read(void* pstatu)      //读取端口线程锁控制
{
	int o;
	while(COM_READ_STATU)
	{
		pthread_mutex_lock(&mut);
    	read_port();
    	pthread_mutex_unlock(&mut);
	}
    pthread_exit(NULL);
}

void* com_send(void* p)           //向端口发送loop内容
{
	int a;
	int ii;
	while(COM_SEND_STATU)
	{
		if(receiving_bit != 0)
		{
			receiving_bit = 0;
			write(fd, first_test, strlen(first_test));			
			if(sendnum<65535)
			{
				sendnum++;
			}
			else
			{
				sendnum_times++;
				sendnum=1;
			}
			msleep(500);	
		}

	
/*		write(fd, first_test, strlen(first_test));		
		if(sendnum<65535)
		{
			sendnum++;
		}
		else
		{
			sendnum_times++;
			sendnum=1;
		}
		msleep(500);			
*/
	}
	pthread_exit(NULL);	
}

int start_thread_func(void*(*func)(void*), pthread_t* pthread, void* par, int* COM_STATU)  //创建线程
{  
    *COM_STATU = 1;  
    memset(pthread, 0, sizeof(pthread_t));  
    int temp;  
    /*creat thread*/  
	if((temp = pthread_create(pthread, NULL, func, par)) != 0)  
	{
		printf("creat thread failer!\n");
	}  
	else  
    {  
        int id = pthread_self();  
        printf("%s,creat thread %lu sucess\n",dev, *pthread);  
    }  
    return temp;  
} 

交叉编译此.c文件,放置开发板目录下方,运行方式:

./编译时输入的名称 /dev/ttymxc2

比如(串口三):
*	arm-linux-gcc uart.c -otty_test -lpthread
*	./tty_test /dev/ttymxc2
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值