怎么办网站平台,企业网站建设的实践意义,嵌入式培训心得,产品介绍彩页模板前言#xff1a; 在Linux系统中#xff0c;串口设备以文件的形式存在#xff0c;通常位于/dev目录下#xff0c;如ttyS0、ttyUSB0等。这些设备文件可以用于读取和写入数据。要使用串口设备#xff0c;需要打开相应的设备文件。在打开串口时#xff0c;可以使用O_RDWR选项… 前言 在Linux系统中串口设备以文件的形式存在通常位于/dev目录下如ttyS0、ttyUSB0等。这些设备文件可以用于读取和写入数据。要使用串口设备需要打开相应的设备文件。在打开串口时可以使用O_RDWR选项标志进行读写操作同时使用O_NOCTTY选项标志告诉Linux“本程序不作为串口的‘控制终端’”以避免一些输入字符影响进程运行。下面让我们对串口应用编程进行一个简单的入门学习吧。 目录 一、串口的作用
二、UART硬件介绍
1.使用串口
2. mini2440
3. JZ2440:
三、TTY体系中设备节点的差别
1.什么是TTY
2.各类设备节点的差别 四、TTY驱动程序的框架
五、回环
1.串口API
2.串口收发实验
六、GPS 模块
1.GPS 模块硬件
2.GPS 模块数据格式 一、串口的作用
UART:通用异步收发传输器(Universal Asynchronous Receiver/Transmitter)简称串口。 调试:移植u-boot、内核、应用程序时主要使用串口查看打印信息 外接各种模块
串口因为结构简单、稳定可靠广受欢迎。
通过三根线即可发送、接收、地线。 二、UART硬件介绍
1.使用串口
1波特率
2格式数据位停止位校验位流量控制 怎么样发送1Byte比如‘A’ A 0x41 0100 0001 (1) 双方约定波特率: 每一位占据的时间假设为1秒 (2) 逻辑电平 如果TTL想转化为RS-232的话需要电平转化芯片
2. mini2440 3. JZ2440: 波特率为115200格式为8n1时每秒可以传输的字节为11520 byte 三、TTY体系中设备节点的差别 /dev/ttySo、/dev/ttySACO、/dev/tty.ldev/tty0、/dev/tty1、/devlconsole, 它们有什么差别? TTYTerminal/ConsolE/UART 它们有什么差别? 1.什么是TTY teletype更准确地说是teleprinter是一种通信设备可以用来发送、接收文本信息。 teletype是一家公司的名字它生产的teleprinter实在太有名结果公司名变成了这类产品的名字:teleprinter都被称为teletype了。
teletype被用来传输商业电报想象一下: 把两台teletype的线缆接在一起或者使用无线技术连接两台telety这边打字另一边就可以接收到信息并诵过纸张打印出来。 将 teletype 的另一端直接与电脑连接起来这样TTY就与计算机关联起来了。 以前的计算机非常的昂贵可能会有很多地方是共用一台电脑通过终端进行操作计算机一个系统存在多个终端。 Terminal和Console的差别 Terminal含有远端的意思中文为:终端。Console翻译为控制台可以理解为权限更大、能查看更多信息。比如我们可以在Console上看到内核的打印信息从这个角度上看: Console是某一个Terminal Terminal并不都是Console。 我们可以从多个Terminal中选择某一个作为Console 很多时候两个概念混用并无明确的、官方的定义 随着时代的发展又出现了新的设备。 随着时代的发展个人电脑和虚拟终端也进入了人们的生活中 在Ubuntu上演示 按住键盘:CtrlAltF3启动一个虚拟终端CtrlAltF4再启动一个虚拟终端。在里面切换为root用户: sudo passwd root //如果su root不成功就先设置root密码su root 2.各类设备节点的差别 /devlconsole 比如: coisolettyS0 consoletty 不想去分辨这个设备是串口还是虚拟端,有没有办法得到这个设备? 有!通过/devlconsole! consolettyS0时: /devlconsole就是ttyso consoletty时:/devlconsole就是前台程序的虚拟终端 consoletty0时: /devlconsole就是前台程序的虚拟终端 consolettyN时:/devlconsole就是/dev/ttyN console有多个取值时使用最后一个取值来判断 四、TTY驱动程序的框架 大多数用户都会在输入时犯错所以退格键会很有用。这当然可以由应用程序本身来实现但是根据UNIX设计哲学应用程序应尽可能保持简单。为了方便起见操作系统提供了一个编辑缓冲区和一些基本的编辑命令(退格清除单个单词清除行重新打印)这些命令在行规范(line discipline)内默认启用。高级应用程序可以通过将行规范设置为原姓模式(raw mode)而不是默认的成熟或准则模式(cooked and canonical)来禁用这些功能。 五、回环
1.串口API 在Linux系统中操作设备的统一接口就是: open/ioctl/read/write。 对于UART又在ioctl之上封装了很多函数主要是用来设置行规程。所以对于UART编程的套路就是: open 设置行规程比如波特率、数据位、停止位、检验位、RAW模式、一有数据就返回 read/write 怎么设置行规程 行规程的参数用结构体 termios 来表示可以参考 Linux 串口—struct termios 结构体
https://blog.csdn.net/yemingzhu163/article/details/5897156 这些函数在名称上有一些惯例 tcterminal contorl cf: control flag 主要是需要设置好 termios 中的参数这些参数很复杂可以参考 Linux 串口—struct termios 结构体。 1 #include stdio.h2 #include string.h3 #include sys/types.h4 #include errno.h5 #include sys/stat.h6 #include fcntl.h7 #include unistd.h8 #include termios.h9 #include stdlib.h1011 /* set_opt(fd,115200,8,N,1) */12 int set_opt(int fd,int nSpeed, int nBits, char nEvent, int nStop)13 {14 struct termios newtio,oldtio;1516 if ( tcgetattr( fd,oldtio) ! 0) {17 perror(SetupSerial 1);18 return -1;19 }2021 bzero( newtio, sizeof( newtio ) );22 newtio.c_cflag | CLOCAL | CREAD;23 newtio.c_cflag ~CSIZE;2425 newtio.c_lflag ~(ICANON | ECHO | ECHOE | ISIG); /*Input*/26 newtio.c_oflag ~OPOST; /*Output*/2728 switch( nBits )29 {30 case 7:31 newtio.c_cflag | CS7;32 break;33 case 8:34 newtio.c_cflag | CS8;35 break;36 }3738 switch( nEvent )39 {40 case O:41 newtio.c_cflag | PARENB;42 newtio.c_cflag | PARODD;43 newtio.c_iflag | (INPCK | ISTRIP);44 break;45 case E:46 newtio.c_iflag | (INPCK | ISTRIP);47 newtio.c_cflag | PARENB;48 newtio.c_cflag ~PARODD;49 break;50 case N:51 newtio.c_cflag ~PARENB;52 break;53 }5455 switch( nSpeed )56 {57 case 2400:58 cfsetispeed(newtio, B2400);59 cfsetospeed(newtio, B2400);60 break;61 case 4800:62 cfsetispeed(newtio, B4800);63 cfsetospeed(newtio, B4800);64 break;65 case 9600:66 cfsetispeed(newtio, B9600);67 cfsetospeed(newtio, B9600);68 break;69 case 115200:70 cfsetispeed(newtio, B115200);71 cfsetospeed(newtio, B115200);72 break;73 default:74 cfsetispeed(newtio, B9600);75 cfsetospeed(newtio, B9600);76 break;77 }7879 if( nStop 1 )80 newtio.c_cflag ~CSTOPB;81 else if ( nStop 2 )82 newtio.c_cflag | CSTOPB;8384 newtio.c_cc[VMIN] 1; /* 读数据时的最小字节数: 没读到这些数据我就不返回! */85 newtio.c_cc[VTIME] 0; /* 等待第1个数据的时间:86 * 比如VMIN设为10表示至少读到10个数据才返回,87 * 但是没有数据总不能一直等吧? 可以设置VTIME(单位是10秒)88 * 假设VTIME1表示:89 * 10秒内一个数据都没有的话就返回90 * 如果10秒内至少读到了1个字节那就继续等待完全读到VMIN个数据再返回91 */9293 tcflush(fd,TCIFLUSH);9495 if((tcsetattr(fd,TCSANOW,newtio))!0)96 {97 perror(com set error);98 return -1;99 }
100 //printf(set done!\n);
101 return 0;
102 }
103
104 int open_port(char *com)
105 {
106 int fd;
107 //fd open(com, O_RDWR|O_NOCTTY|O_NDELAY);
108 fd open(com, O_RDWR|O_NOCTTY);
109 if (-1 fd){
110 return(-1);
111 }
112
113 if(fcntl(fd, F_SETFL, 0)0) /* 设置串口为阻塞状态*/
114 {
115 printf(fcntl failed!\n);
116 return -1;
117 }
118
119 return fd;
120 }
121
122
123 /*
124 * ./serial_send_recv dev
125 */
126 int main(int argc, char **argv)
127 {
128 int fd;
129 int iRet;
130 char c;
131
132 /* 1. open */
133
134 /* 2. setup
135 * 115200,8N1
136 * RAW mode
137 * return data immediately
138 */
139
140 /* 3. write and read */
141
142 if (argc ! 2)
143 {
144 printf(Usage: \n);
145 printf(%s /dev/ttySAC1 or other\n, argv[0]);
146 return -1;
147 }
148
149 fd open_port(argv[1]);
150 if (fd 0)
151 {
152 printf(open %s err!\n, argv[1]);
153 return -1;
154 }
155
156 iRet set_opt(fd, 115200, 8, N, 1);
157 if (iRet)
158 {
159 printf(set port err!\n);
160 return -1;
161 }
162
163 printf(Enter a char: );
164 while (1)
165 {
166 scanf(%c, c);
167 iRet write(fd, c, 1);
168 iRet read(fd, c, 1);
169 if (iRet 1)
170 printf(get: %02x %c\n, c, c);
171 else
172 printf(can not get data\n);
173 }
174
175 return 0;
176 } 第152行 打开设备节点 第156行设置波特率和格式 164 while (1)
165 {
166 scanf(%c, c);
167 iRet write(fd, c, 1);
168 iRet read(fd, c, 1);
169 if (iRet 1)
170 printf(get: %02x %c\n, c, c);
171 else
172 printf(can not get data\n);
173 }第164~173行 进入循环后等待用户输入数据得到数据后发给指定的串口再读取指定串口上的数据读到后在命令行中打印出来 104 int open_port(char *com) 第104~120行打开设备节点 第113行 1.fcntl (fd,FSETFL,FNDELAY);读数据时不等待没有数据就返回0 2.fcntl (fd, F_SETFL,0);读数据时没有数据阻塞 12 int set_opt(int fd,int nSpeed, int nBits, char nEvent, int nStop)第12~102行 设置波特率和格式 2.串口收发实验 通过把串口的发送、接收引脚短接实现自发自收使用 write 函数 发出字符使用 read 函数读取字符。 1. Ubuntu 上
arm-buildroot-linux-gnueabihf-gcc -o serial_send_recv serial_send_recv.c
2. 板子上
/mnt/serial_send_recv /dev/ttymxc5 六、GPS 模块 全球定位系统(Global Positioning SystemGPS)是一种以空中卫星为 基础的高精度无线电导航的定位系统它在全球任何地方以及近地空间都能够提 供准确的地理位置、车行速度及精确的时间信息。GPS 主要由三大组成部分空 间部分、地面监控部分和用户设备部分。GPS 系统具有高精度、全天候、用广泛 等特点。
1.GPS 模块硬件 GPS 模块与外部控制器的通讯接口有多种方式这里我们使用串口进行通讯 波特率为 9600bps,1bit 停止位无校验位无流控默认每秒输出一次标准格式数据。 2.GPS 模块数据格式 GPS 使用多种标准数据格式目前最通用的 GNSS 格式是 NMEA0183 格式。 NMEA0183 是最终定位格式即将二进制定位格式转为统一标准定位格式与卫星类型无关。这是一套定义接收机输出的标准信息有几种不同的格式每种都是独立相关的 ASCII 格式逗点隔开数据流数据流长度从 30-100 字符不等 通常以每秒间隔持续输出。 我们使用串口接收数据收到的数据包含$GPGGAGPS 定位数据、$GPGLL 地理定位信息、$GPGSA当前卫星信息、$GPGSV可见卫星状态信息、 $GPRMC推荐最小定位信息、$GPVTG地面速度信息。 这里我们只分析$GPGGA (Global Positioning System Fix Data)即可 它包含了 GPS 定位经纬度、质量因子、HDOP、高程、参考站号等字段。其标准格式如下 $XXGGA 语句各字段的含义和取值范围各字段的含义和取值范围见下表所示 XX 取值有 ◼ GPGGA单 GPS BDGGA单北斗 GLGGA单 GLONASS GNGGA多星联合定位 例子$GPGGA074529.822429.6717N11804.6973E181.098 42.110M*76。 1 #include stdio.h2 #include string.h3 #include sys/types.h4 #include errno.h5 #include sys/stat.h6 #include fcntl.h7 #include unistd.h8 #include termios.h9 #include stdlib.h1011 /* set_opt(fd,115200,8,N,1) */12 int set_opt(int fd,int nSpeed, int nBits, char nEvent, int nStop)13 {14 struct termios newtio,oldtio;1516 if ( tcgetattr( fd,oldtio) ! 0) {17 perror(SetupSerial 1);18 return -1;19 }2021 bzero( newtio, sizeof( newtio ) );22 newtio.c_cflag | CLOCAL | CREAD;23 newtio.c_cflag ~CSIZE;2425 newtio.c_lflag ~(ICANON | ECHO | ECHOE | ISIG); /*Input*/26 newtio.c_oflag ~OPOST; /*Output*/2728 switch( nBits )29 {30 case 7:31 newtio.c_cflag | CS7;32 break;33 case 8:34 newtio.c_cflag | CS8;35 break;36 }3738 switch( nEvent )39 {40 case O:41 newtio.c_cflag | PARENB;42 newtio.c_cflag | PARODD;43 newtio.c_iflag | (INPCK | ISTRIP);44 break;45 case E:46 newtio.c_iflag | (INPCK | ISTRIP);47 newtio.c_cflag | PARENB;48 newtio.c_cflag ~PARODD;49 break;50 case N:51 newtio.c_cflag ~PARENB;52 break;53 }5455 switch( nSpeed )56 {57 case 2400:58 cfsetispeed(newtio, B2400);59 cfsetospeed(newtio, B2400);60 break;61 case 4800:62 cfsetispeed(newtio, B4800);63 cfsetospeed(newtio, B4800);64 break;65 case 9600:66 cfsetispeed(newtio, B9600);67 cfsetospeed(newtio, B9600);68 break;69 case 115200:70 cfsetispeed(newtio, B115200);71 cfsetospeed(newtio, B115200);72 break;73 default:74 cfsetispeed(newtio, B9600);75 cfsetospeed(newtio, B9600);76 break;77 }7879 if( nStop 1 )80 newtio.c_cflag ~CSTOPB;81 else if ( nStop 2 )82 newtio.c_cflag | CSTOPB;8384 newtio.c_cc[VMIN] 1; /* 读数据时的最小字节数: 没读到这些数据我就不返回! */85 newtio.c_cc[VTIME] 0; /* 等待第1个数据的时间:86 * 比如VMIN设为10表示至少读到10个数据才返回,87 * 但是没有数据总不能一直等吧? 可以设置VTIME(单位是10秒)88 * 假设VTIME1表示:89 * 10秒内一个数据都没有的话就返回90 * 如果10秒内至少读到了1个字节那就继续等待完全读到VMIN个数据再返回91 */9293 tcflush(fd,TCIFLUSH);9495 if((tcsetattr(fd,TCSANOW,newtio))!0)96 {97 perror(com set error);98 return -1;99 }
100 //printf(set done!\n);
101 return 0;
102 }
103
104 int open_port(char *com)
105 {
106 int fd;
107 //fd open(com, O_RDWR|O_NOCTTY|O_NDELAY);
108 fd open(com, O_RDWR|O_NOCTTY);
109 if (-1 fd){
110 return(-1);
111 }
112
113 if(fcntl(fd, F_SETFL, 0)0) /* 设置串口为阻塞状态*/
114 {
115 printf(fcntl failed!\n);
116 return -1;
117 }
118
119 return fd;
120 }
121
122
123 int read_gps_raw_data(int fd, char *buf)
124 {
125 int i 0;
126 int iRet;
127 char c;
128 int start 0;
129
130 while (1)
131 {
132 iRet read(fd, c, 1);
133 if (iRet 1)
134 {
135 if (c $)
136 start 1;
137 if (start)
138 {
139 buf[i] c;
140 }
141 if (c \n || c \r)
142 return 0;
143 }
144 else
145 {
146 return -1;
147 }
148 }
149 }
150
151 /* eg. $GPGGA,082559.00,4005.22599,N,11632.58234,E,1,04,3.08,14.6,M,-5.6,M,,*76CRLF */
152 int parse_gps_raw_data(char *buf, char *time, char *lat, char *ns, char *lng, char *ew)
153 {
154 char tmp[10];
155
156 if (buf[0] ! $)
157 return -1;
158 else if (strncmp(buf3, GGA, 3) ! 0)
159 return -1;
160 else if (strstr(buf, ,,,,,))
161 {
162 printf(Place the GPS to open area\n);
163 return -1;
164 }
165 else {
166 //printf(raw data: %s\n, buf);
167 sscanf(buf, %[^,],%[^,],%[^,],%[^,],%[^,],%[^,], tmp, time, lat, ns, lng, ew);
168 return 0;
169 }
170 }
171
172
173 /*
174 * ./serial_send_recv dev
175 */
176 int main(int argc, char **argv)
177 {
178 int fd;
179 int iRet;
180 char c;
181 char buf[1000];
182 char time[100];
183 char Lat[100];
184 char ns[100];
185 char Lng[100];
186 char ew[100];
187
188 float fLat, fLng;
189
190 /* 1. open */
191
192 /* 2. setup
193 * 115200,8N1
194 * RAW mode
195 * return data immediately
196 */
197
198 /* 3. write and read */
199
200 if (argc ! 2)
201 {
202 printf(Usage: \n);
203 printf(%s /dev/ttySAC1 or other\n, argv[0]);
204 return -1;
205 }
206
207 fd open_port(argv[1]);
208 if (fd 0)
209 {
210 printf(open %s err!\n, argv[1]);
211 return -1;
212 }
213
214 iRet set_opt(fd, 9600, 8, N, 1);
215 if (iRet)
216 {
217 printf(set port err!\n);
218 return -1;
219 }
220
221 while (1)
222 {
223 /* eg. $GPGGA,082559.00,4005.22599,N,11632.58234,E,1,04,3.08,14.6,M,-5.6,M,,*76CRLF*/
224 /* read line */
225 iRet read_gps_raw_data(fd, buf);
226
227 /* parse line */
228 if (iRet 0)
229 {
230 iRet parse_gps_raw_data(buf, time, Lat, ns, Lng, ew);
231 }
232
233 /* printf */
234 if (iRet 0)
235 {
236 printf(Time : %s\n, time);
237 printf(ns : %s\n, ns);
238 printf(ew : %s\n, ew);
239 printf(Lat : %s\n, Lat);
240 printf(Lng : %s\n, Lng);
241
242 /* 纬度格式: ddmm.mmmm */
243 sscanf(Lat2, %f, fLat);
244 fLat fLat / 60;
245 fLat (Lat[0] - 0)*10 (Lat[1] - 0);
246
247 /* 经度格式: dddmm.mmmm */
248 sscanf(Lng3, %f, fLng);
249 fLng fLng / 60;
250 fLng (Lng[0] - 0)*100 (Lng[1] - 0)*10 (Lng[2] - 0);
251 printf(Lng,Lat: %.06f,%.06f\n, fLng, fLat);
252 }
253 }
254
255 return 0;
256 }
257 123 int read_gps_raw_data(int fd, char *buf)第123行对应到255行GPS原始数据读取一行数据 152 int parse_gps_raw_data(char *buf, char *time, char *lat, char *ns, char *lng, char *ew)第151~170行进行数据解析 167 sscanf(buf, %[^,],%[^,],%[^,],%[^,],%[^,],%[^,], tmp, time, lat, ns, lng, ew);注%[^] 剔除不包含符合 第181~186 定义这五个数据 第228行iRet 0表明读到数据 第234~252行读到数据并进行数据解析如果解析成功则将这些信息打印出来 第181~186行 定义这五个数据。
第242~251行将经纬度转变并且打印出来。 1. Ubuntu 上
arm-buildroot-linux-gnueabihf-gcc -o gps_read gps_read.c
2. 板子上
/mnt/gps_read /dev/ttymxc5