树莓派进阶之路 (041) - 串口篇 - 使用系统软串口(/dev/ttyS0)进行通信

系统环境:

  主机:Linux ubuntu 5.4.0-45-generic #49~18.04.2-Ubuntu SMP Wed Aug 26 16:29:02 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux

  树莓派:Linux raspberrypi 4.19.97-v7+ #1294 SMP Thu Jan 30 13:15:58 GMT 2020 armv7l GNU/Linux

 

串口要求以及相关配置方案:

// -------------------------------------------------------------------------------------------------------- 华丽的分割线 --------------------------------------------------------------------------------------------------------------------------

简单的使用串口通信,波特率要求不高(波特率500k以下),可以简单的配置使用:

1、简单配置通系统通信串口:使用《树莓派进阶之路 (022) - 串口篇 - 通过串口连接控制树莓派》配置结果如下:

 

 

2、通过  raspi-config 关闭系统和串口的链接(Interfacing Options => Serial =》Select =》ok =》Finish )

选择:Interfacing Options

 

选择:Serial-》Select

 

 选择:ok

 选择:Finish

 3、删除配置启动引导配置文件(/boot/cmdline.txt)的串口配置(console=serial0,115200)

sudo vim /boot/cmdline.txt

 4、重启(reboot)

 5、文件测试

main.c

  1 #include <stdio.h>
  2 #include <string.h>
  3 #include <errno.h>
  4 #include <unistd.h>
  5 #include <stdlib.h>
  6 #include <stdio.h>
  7 #include <stdlib.h>
  8 #include <stdint.h>
  9 #include <stdarg.h>
 10 #include <string.h>
 11 #include <termios.h>
 12 #include <unistd.h>
 13 #include <fcntl.h>
 14 #include <sys/ioctl.h>
 15 #include <sys/types.h>
 16 #include <sys/stat.h>
 17 
 18 #define par_type  long
 19 
 20 // ----------------------------------------------------------------------------------------
 21 int serialOpen (const char *device, const long baud)
 22 {
 23   struct termios options ;
 24   speed_t myBaud ;
 25   int     status, fd ;
 26 
 27   switch (baud)
 28   {
 29     case      50:    myBaud =      B50 ; break ;
 30     case      75:    myBaud =      B75 ; break ;
 31     case     110:    myBaud =     B110 ; break ;
 32     case     134:    myBaud =     B134 ; break ;
 33     case     150:    myBaud =     B150 ; break ;
 34     case     200:    myBaud =     B200 ; break ;
 35     case     300:    myBaud =     B300 ; break ;
 36     case     600:    myBaud =     B600 ; break ;
 37     case    1200:    myBaud =    B1200 ; break ;
 38     case    1800:    myBaud =    B1800 ; break ;
 39     case    2400:    myBaud =    B2400 ; break ;
 40     case    4800:    myBaud =    B4800 ; break ;
 41     case    9600:    myBaud =    B9600 ; break ;
 42     case   19200:    myBaud =   B19200 ; break ;
 43     case   38400:    myBaud =   B38400 ; break ;
 44     case   57600:    myBaud =   B57600 ; break ;
 45     case  115200:    myBaud =  B115200 ; break ;
 46     case  230400:    myBaud =  B230400 ; break ;
 47     case  460800:    myBaud =  B460800 ; break ;
 48     case  500000:    myBaud =  B500000 ; break ;
 49     case  576000:    myBaud =  B576000 ; break ;
 50     case  921600:    myBaud =  B921600 ; break ;
 51     case 1000000:    myBaud = B1000000 ; break ;
 52     case 1152000:    myBaud = B1152000 ; break ;
 53     case 1500000:    myBaud = B1500000 ; break ;
 54     case 2000000:    myBaud = B2000000 ; break ;
 55     case 2500000:    myBaud = B2500000 ; break ;
 56     case 3000000:    myBaud = B3000000 ; break ;
 57     case 3500000:    myBaud = B3500000 ; break ;
 58     case 4000000:    myBaud = B4000000 ; break ;
 59 
 60     default:
 61       return -2 ;
 62   }
 63 
 64   if ((fd = open (device, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK)) == -1)
 65     return -1 ;
 66 
 67   fcntl (fd, F_SETFL, O_RDWR) ;
 68 
 69 // Get and modify current options:
 70 
 71   tcgetattr (fd, &options) ;
 72 
 73     cfmakeraw   (&options) ;
 74     cfsetispeed (&options, myBaud) ;
 75     cfsetospeed (&options, myBaud) ;
 76 
 77     options.c_cflag |= (CLOCAL | CREAD) ;
 78     options.c_cflag &= ~PARENB ;
 79     options.c_cflag &= ~CSTOPB ;
 80     options.c_cflag &= ~CSIZE ;
 81     options.c_cflag |= CS8 ;
 82     options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG) ;
 83     options.c_oflag &= ~OPOST ;
 84 
 85     options.c_cc [VMIN]  =   0 ;
 86     options.c_cc [VTIME] = 100 ;    // Ten seconds (100 deciseconds)
 87 
 88   tcsetattr (fd, TCSANOW, &options) ;
 89 
 90   ioctl (fd, TIOCMGET, &status);
 91 
 92   status |= TIOCM_DTR ;
 93   status |= TIOCM_RTS ;
 94 
 95   ioctl (fd, TIOCMSET, &status);
 96 
 97   usleep (10000) ;    // 10mS
 98 
 99   return fd ;
100 }
101 // ----------------------------------------------------------------------------------------
102 struct  serial_test_data{
103     int fd;
104     unsigned int Features;
105     unsigned char buf[1024];
106     unsigned long long  H_count;
107     unsigned long long  L_count;
108 };
109 // ----------------------------------------------------------------------------------------
110 long baud_value;
111 // 传参处理函数
112 // main  收发状态 波特率 设备地址  发送数据
113 int main_Parameter_handling_function(par_type serial_addr, int argc, char* argv[]){
114     struct  serial_test_data *serial = (struct  serial_test_data *)serial_addr;
115     baud_value = 115200;
116     if(1 == argc){printf("请配置参数: 0 发送模式,1接受模式\n");printf("请配置波特率:默认115200\n");return 1;}
117     if(argc == 2){printf("默认115200\n");if(0 == atoi(argv[1]))serial->Features = 0;else if(1 == atoi(argv[1]))serial->Features = 1;}
118     if(argc == 3){
119         if(0 == atoi(argv[1]))serial->Features = 0;
120         else if(1 == atoi(argv[1]))serial->Features = 1;
121         baud_value = atoi(argv[2]);
122     }
123     return 0;
124 }
125 //  串口
126 int Serial_Parameter_handling_function(par_type serial_addr,const long baud,const char * serial_device){
127     struct  serial_test_data *serial = (struct  serial_test_data *)serial_addr;
128     int ret ;
129     if ((serial->fd = serialOpen (serial_device, baud)) < 0){
130         fprintf (stderr, "Unable to open serial device: %s\n", strerror (errno)) ;
131         ret = 1 ;
132   }else {
133       tcflush (serial->fd, TCIOFLUSH) ;
134       memset(serial->buf,0,strlen(serial->buf));
135       serial-> H_count = 0;
136       serial-> L_count = 0;
137       ret =  0;
138   }
139   return ret;
140 }
141 // ----------------------------------------------------------------------------------------
142 // ----------------------- write
143 // char
144 void Serial_write_char(const int fd, const unsigned char c){write (fd, &c, 1) ;}
145 //  string
146 void Serial_write_string(const int fd, const char *s){write (fd, s, strlen (s));}
147 //  ----------------------- read
148 int Serial_read_char(const int fd){
149     unsigned char x ;
150     if (read (fd, &x, 1) != 1)return -1 ;
151     return ((int)x) & 0xFF ;
152 }
153 // ----------------------------------------------------------------------------------------
154 void Serial_data(par_type serial_addr,const char *s){
155     struct  serial_test_data *serial = (struct  serial_test_data *)serial_addr;
156     int len =  write (serial->fd, s, strlen (s));
157   //  printf("len = %d  strlen (s) = %d\n",len,strlen (s));
158     if(len == strlen (s)){
159       serial->L_count = serial->L_count + strlen (s);
160         if (serial->L_count > 1000000000) {
161           serial->L_count = serial->L_count - 1000000000;
162           serial-> H_count = serial-> H_count + 1;
163         }
164     }
165 }
166 // ----------------------------------------------------------------------------------------
167 int main(int argc, char *argv[]){
168     struct serial_test_data serial0;
169     int ret;
170     if(main_Parameter_handling_function((par_type)&serial0,argc,argv))return 1;            // main 函数处理
171     if(Serial_Parameter_handling_function((par_type)&serial0,baud_value,"/dev/serial0"));  //  串口处理函数
172     while(1){
173       if (0 == serial0.Features){
174         sprintf(serial0.buf,"jikexianfeng %lld\n",serial0.L_count);
175         Serial_data((par_type)&serial0,serial0.buf);
176       }
177       else if (1 == serial0.Features) printf("%c", Serial_read_char(serial0.fd));
178       else{
179         close(serial0.fd);ret = 1;
180       }
181     }
182     return ret;
183 }

编译:gcc main.c -o main

1 sudo ./main 收发模式 波特率(可省略,默认115200)
2 sudo ./main 0     // 发送模式
3 sudo ./main 1     // 接收模式

// -------------------------------------------------------------------------------------------------------- 华丽的分割线 --------------------------------------------------------------------------------------------------------------------------

默认stc51单片机举例,代码方法比较全面,选择适合的自己的就行。

本代码默认支持8位的lcd排灯,需要扩列的自行修改代码。

创作不易,转载说明出处,谢谢!

 // --------------------------------------------------------------------------------------------------------

posted @ 2020-09-07 11:20  极客先锋  阅读(2186)  评论(0编辑  收藏  举报