linux 与 单片机 串口通信

来源:互联网 发布:阿里云课堂 编辑:程序博客网 时间:2024/04/19 18:00

  本人最近在尝试在linux下用串口与单片机通信,虽然说网上资料例程五花八门,但是缺乏严格的注释或者完整的实例,或许本人能力有限,某些问题无法理解,在实际过程中遇到不少问题,无从下手,特此写篇文章请求各位大神的斧正。初次写帖,不足处希望指出。

  实验目的:单片机通过串口向linux发送数据。

  环境:单片机 ST90C516RD+,使用USB转串口(驱动PL2303);linux(ubuntu11.10)装载在VM8。

  单片机发送程序如下

/********************************************************************* 文件名  : 串口发送试验.c* 描述    :  该文件实现通过串口把数据从单片机发送到电脑,通过串口调试助手显示出来。 晶振需要用11.0592的。***********************************************************************/#include<reg52.h>#include<intrins.h>#define uchar unsigned char#define uint  unsigned int /********************************************************************* 名称 : Com_Init()* 功能 : 初始化串口程序,晶振11.0592, 波特率9600* 输入 : 无* 输出 : 无***********************************************************************/void Com_Init(void){     TMOD = 0x20;     PCON = 0x00;     SCON = 0x50;     TH1 = 0xFd;     TL1 = 0xFd;     TR1 = 1;}void delay_ms(unsigned int n)            //延时10×n毫秒程序{unsigned int i,j;for(i=0;i<n;i++)for(j=0;j<2000;j++);}/********************************************************************* 名称 : Main()* 功能 : 主函数* 输入 : 无* 输出 : 无***********************************************************************/void Main(){char i = 0;char code Buffer[] = "abcdef 123456 ABCDEF";char *p;Com_Init();P2 = 0x00;while(1){p = Buffer;while(1){SBUF = *p;while(!TI)                   //如果发送完毕,硬件会置位TI = 1{_nop_();//延时一个指令周期}p++;if(*p == '\0') break;//在每个字符串的最后,会有一个'\0'TI = 0;                //TI清零}TI = 0;                //TI清零delay_ms(100);}}

linux C代码如下

#include     <stdio.h>#include     <stdlib.h> #include     <unistd.h>  #include     <sys/types.h>#include     <sys/stat.h>#include     <fcntl.h> #include     <termios.h>#include     <errno.h>#include  <string.h>#define SERIAL_PORT"/dev/ttyUSB0"//串口地址#define PORT_SPEED9600//串口波特率#defineDATABITS8//数据位#define STOPBITS1//停止位#definePARITY'n'//校验方式 (不校验)int speed_arr[] = {B38400, B19200, B9600, B4800, B2400, B1200, B300,B38400, B19200, B9600, B4800, B2400, B1200, B300,};int name_arr[] = {38400,  19200,  9600,  4800,  2400,  1200,  300, 38400,  19200,  9600, 4800, 2400, 1200,  300,};int setSpeed(int, int, struct termios);int setParity(int, int, int, int, struct termios);int openPort(void);int init(void);void readPort(int);int main(){char *quit = (char*)malloc(sizeof(char*));int fd;         char write_buf[256];fd = init();//初始化端口设置printf("configure complete\n");   printf("start send and receive data...\n");    while(1)  {          readPort(fd);}close(fd);}void readPort(int fd){int i;  int len;  int n;   char read_buf[256];  while(1)  {bzero(read_buf, sizeof(read_buf));         while((n = read(fd, read_buf, sizeof(read_buf))) > 0)  {printf("Len %d \n", n);read_buf[n + 1] = '\0';  printf("[%s]\n", read_buf);  }  }}/************************************ *init  *初始化串口 *@global *PORT_SPEED串口波特率 *DATABITS数据位 *STOPBITS停止位 *PARITY校验方式 *@return *-1:设置失败  !(-1):设置成功 ************************************/int init(void){int fd;struct termios opt;//定义termios结构 /*  这个变量被用来提供一个健全的线路设置集合, 如果这个端口在被用户初始化前  使用. 驱动初始化这个变量使用一个标准的数值集                 struct termios{  unsigned short c_iflag; //输入模式标志    unsigned short c_oflag; //输出模式标志    unsigned short c_cflag; //控制模式标志    unsigned short c_lflag; //区域模式标志或本地模式标志或局部模式    unsigned char c_line; //行控制line discipline     unsigned char c_cc[NCC]; // 控制字符特性  };*/  //打开串口  fd = openPort();    //设置波特率  if(setSpeed(fd, PORT_SPEED, opt) == 1)  {  printf("setSpeed failed!\n");  exit(1);  }    //设置数据位、停止位和校验位  if(setParity(fd, DATABITS, STOPBITS, PARITY, opt) == 1)  {  printf("setParity failed!\n");  exit(1);  }   if(tcsetattr(fd, TCSANOW, &opt) != 0)//TCSANOW:不等数据传输完毕就立即改变属性。{//TCSADRAIN:等待所有数据传输结束才改变属性。      perror("serial error");      return -1;  }  return fd;}/************************************ *openPort   *打开串口 *@global *SERIAL_PORT串口地址 *@return *-1:设置失败  !(-1):设置成功 ************************************/int openPort(){int fd;//O_RDWR:可读写方式打开;//O_NOCTTY:若打开的文件为终端机设备时则不会把该终端机当做进程控制终端机//O_NDELAY:以不可阻断的方式打开文件fd = open(SERIAL_PORT, O_RDWR | O_NOCTTY |O_NDELAY);     if(fd == -1)  {perror("open serial failed!\n");  exit(1);  }      return fd;}/************************************ *setSpeed   *设置波特率(38400, 19200, 9600, 4800, 2400, 1200, 300) *@para *fd文件标识。 *speed波特率。 *  struct termiostermios结构变量 *@return *1:设置失败  0:设置成功 ************************************/int setSpeed(int fd, int speed, struct termios Opt){    int i;    //if(tcgetattr(fd, &Opt) != 0) //获取与终端相关的参数;#并将获得信息保存在 opt 变量中    if(tcgetattr(STDIN_FILENO, &Opt) != 0)    {        perror("tcgetattr fd\n");        return 1;    }    //识别波特率,设置输入输出波特率    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]);                        //设置数据接收方式            if(tcsetattr(fd, TCSANOW, &Opt) != 0)            {                perror("tcsetattr fd");                return 1;            }            tcflush(fd, TCIOFLUSH);        }    }    return 0;}/************************************ *setParity  *设置数据位、停止位和校验位 *@para *fd文件标识。 *databits数据位。(8 | 7) *stopbits停止位。(1 | 2) *parity校验位。(n:无校验位 | o:奇校验 | e:偶校验 | s:空格) *@return *1:设置失败  0:设置成功 ************************************/int setParity(int fd, int databits, int stopbits, int parity, struct termios Opt){    if(tcgetattr(fd, &Opt) != 0)    {        perror("tcgetattr fd");        return 1;    }Opt.c_cflag |= (CLOCAL | CREAD);       //CLOCAL:忽略 modem 控制线。 //CREAD:打开接受者。    switch(databits)       //设置数据位数    {    case 7:        Opt.c_cflag &= ~CSIZE;//屏蔽字符大小位        Opt.c_cflag |= CS7;//选择7位数据位        break;    case 8:        Opt.c_cflag &= ~CSIZE;        Opt.c_cflag |= CS8;        break;    default:        fprintf(stderr, "Unsupported data size.\n");        return 1;    }    switch(parity)            //设置校验位    {    case 'n':        Opt.c_cflag &= ~PARENB;        //清除校验位        Opt.c_iflag &= ~INPCK;        //启用输入奇偶检测。          break;    case 'o':        Opt.c_cflag |= PARENB;       //使能校验位        Opt.c_cflag |= PARODD;        //奇校验        Opt.c_iflag |= INPCK;            //启用输入奇偶检测。        break;    case 'e':        Opt.c_cflag |= PARENB;       //使能校验位        Opt.c_cflag &= ~PARODD;        //偶校验        Opt.c_iflag |= INPCK;            //启用输入奇偶检测。        break;    case 's':        Opt.c_cflag &= ~PARENB;        //清除校验位        Opt.c_cflag &= ~CSTOPB;       //设置一个停止位        Opt.c_iflag |= INPCK;            //启用输入奇偶检测。        break;    default:        fprintf(stderr, "Unsupported parity.\n");        return 1;        }    switch(stopbits)        //设置停止位    {    case 1:        Opt.c_cflag &= ~CSTOPB;        break;    case 2:        Opt.c_cflag |= CSTOPB;        break;    default:        fprintf(stderr, "Unsupported stopbits.\n");        return 1;    }    Opt.c_cflag |= (CLOCAL | CREAD);    Opt.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);     Opt.c_oflag &= ~OPOST;//OPOST :启用具体实现自行定义的输出处理。    Opt.c_oflag &= ~(ONLCR | OCRNL);    //OCRNL :将输出中的回车映射为新行符   //ONLCR :(XSI) 将输出中的新行符映射为回车-换行。        Opt.c_iflag &= ~(ICRNL | INLCR);//ICRNL :将输入中的回车翻译为新行 (除非设置了 IGNCR)(否则当输入信号有 CR 时不会终止输入)。     //INLCR :将输入中的 NL 翻译为 CR。(将收到的换行符号转换为Return)    Opt.c_iflag &= ~(IXON | IXOFF | IXANY);//IXON :启用输出的 XON/XOFF 流控制。    //IXOFF :启用输入的 XON/XOFF 流控制。//IXANY :(不属于 POSIX.1;XSI) 允许任何字符来重新开始输出。    tcflush(fd, TCIFLUSH);//清空输入缓存        //MIN = 0 , TIME =0; 有READ立即回传否则传回 0,不读取任何字元    Opt.c_cc[VTIME] = 0;            Opt.c_cc[VMIN] = 0;                if(tcsetattr(fd, TCSANOW, &Opt) != 0)//设置数据接收方式    {        perror("tcsetattr fd");        return 1;    }    return 0;}

 

在win7使用串口助手时,能正常接收数据,没有数据错误出现。

在linux首次使用minicom时,能正常接收数据,没有数据错误出现。

然而在运行C以后,开始出现乱码:

乱码有如下两种情况:

1.特殊字符
 

2.接收时序错误

 

实在不知如何解决,后续问题将跟帖提出,特此求助。

原创粉丝点击