根据官方信息(https://www.raspberrypi.org/documentation/configuration/uart.md),树莓派ZeroW的CPU内部有两个串口,一个PL001 UART和一个Mini UART。其中Mini UART没有时钟源,必须由内核提供时钟源。因为内核频率本身是变化的,从而导致Mini UART速率不稳,基本无法使用。另外树莓派ZeroW没有将PL011 UART分配GPIO中的UART(GPIO14和GPIO15)上,而是将其分配给了蓝牙模块。所以我们需要关闭蓝牙释放PL011 UART转移到GPIO14/15上,才能正常使用PL011 UART。
【1】查看映射关系
$ sudo ls -l /dev
如上图所示:serial0是GPIO14/15上的UART,ttyAMA0是PL001 UART,这是我已经修改好环境将两者连接起来的结果。
(1)修改cmdline.txt文件
$ sudo vim /boot/cmdline.txt
删除console对应的字段
(2)关闭板载蓝牙
$ sudo systemctl disable hciuart
编辑config.txt文件
$ sudo vim /boot/config.txt
增加如下一行:
dtoverlay=pi3-disable-bt
重启树莓派
$ sudo reboot
(3)禁用串口的控制台功能
再次编辑config.txt文件,增加如下一行:
enable_uart=1
然后重启树莓派
至此GPIO14/15的UART串口应该就能正常使用了。
函数 | 功能 | 参数 | 返回值 | 备注 | |
1 | int serialOpen (char *device, int baud) | 打开并初始化串口 | device 串口的地址,也就是Linux中就是设备所在的目录,树莓派ZeroW用的是"/dev/ttyAMA0"。
baud 波特率 | 正常返回文件描述符,否则返回-1失败。 | |
2 | void serialClose (int fd) | 关闭fd关联的串口 | fd 文件描述符 | ||
3 | void serialPutchar (int fd, unsigned char c) | 串口发送一个字节的数据 | fd 文件描述符
c 要发送的数据 | ||
4 | void serialPuts (int fd, char *s) | 串口发送一个字符串 | fd 文件描述符
s 发送的字符串,字符串要以’\0’结尾 | ||
5 | void serialPrintf (int fd, char *message) | 和系统函数printf一样发送数据到串口 | fd 文件描述符
message 格式化的字符串 | 系统函数printf是将信息打印到shell中 | |
6 | int serialDataAvail (int fd) | 获取串口接收缓存中的字节数,以便后续能准确接收。 | fd 文件描述符 | 串口缓存中已经接收的,可读取的字节数,如果返回-1表示错误 | |
7 | int serialGetchar (int fd) | 从串口缓存中读取一个字节数据 | fd 文件描述符 | 读取到的字符,如果串口缓存中没有可用的数据,则会等待10秒,如果10后还有没,返回-1。 | 为了提高接收效率,在读取缓存前,先获取接收缓存的有效字节数,然后根据需要读取,避免出现等待。 |
8 | void serialFlush (int fd) | 刷新,清空串口缓冲中的所有可用的数据 | fd 文件描述符 | ||
9 | size_t write (int fd,const void * buf,size_t count) | 这个是Linux下的标准IO库函数,需要包含头文件#include <unistd.h>,用于通过串口大量发送数据。 | buf 需要发送的数据缓存数组
count 发送buf中的前count个字节数据 | 实际写入缓存的字符数,错误返回-1 | 当要需要大量发送时,wiringPi建议使用这个函数。 |
10 | size_t read(int fd,void * buf ,size_t count) | 这个是Linux下的标准IO库函数,需要包含头文件#include <unistd.h>,用于通过串口大量接收数据。 | buf 接收的数据缓存数组
count 接收的字节数 | 实际从缓存中读取的字符数 | 当要需要大量接收时,wiringPi建议使用这个函数。 |
#include <stdio.h> #include <errno.h> #include <string.h> #include <wiringSerial.h> //使用wiringPi串口函数库 int main(int argc, char *argv[]) { int fd; if ((fd = serialOpen("/dev/ttyAMA0", 115200)) < 0) //初始化串口并获取文件描述符保存到fd变量里 { fprintf(stderr, "Unable to open serial device: %s\n", strerror(errno)); return 1 ; } serialPuts(fd, "Raspi Zero W UART Test Start!"); for (;;) { if (serialDataAvail(fd) > 0) //查询接收缓存是否有数据 { serialPutchar(fd,serialGetchar(fd)); //从接收缓存中读取一个字节数据并送入发送缓存中,实现串口环回。 } } return 0; }
将上述代码保存为uart_inout.c
$ gcc uart_inout.c -o uart_inout -l wiringPi
编译后输出uart_inout文件并执行
$ ./uart_inout