树莓派开发相关知识六 -串口通讯
1、uart串口通信
uart串口通信协议,使用txd,rxd双引脚实行异步数据传输,其中txd为传输口,rxd为接收口。
其协议如上图,由起始位+有效数据位+奇偶校验位(*可选),停止位(*宽度可调),空闲位组成,即根据uart协议,当我们需要发送如01010101这8位有 效数据时,我们应该让txd引脚成010101010(LSB低位在前) (0/1根据奇校验,偶校验还是无奇偶校验定) 1(1/1.5/2 脉冲宽度可以是1,1.5,2),后续如果不发数据了,则停留在空闲位。
如果我们选择有效位8位数据,奇校验并停止位宽度为1,则发送数据时发送 01010100111即可。
- 空闲位:即不发数据时的默认位,取1
- 起始位:取0,空闲位拉低表示“我要发数据了”,接收端监听低位就知道“你发数据了”,当然这是异步通信,数据收发不“负责”,只管发跟收,没有 ack回应。
- 有效数据位:低位在前,即先发低位
- 奇偶校验位:根据协议可设置为奇校验,偶校验,无奇偶校验,奇校验则上述有效位+校验位加起来为奇数,偶校验则有效位+校验位为偶数,无 则没有这个时序
- 停止位:取1,即拉高表示数据传输结束,保持1/1.5/2个脉冲宽度,可根据协议调整
由于是异步通信,因此收发两端必须通过某种方式进行同步,此同步方式为波特率,所谓波特率即一秒钟有多少个位传输,如115200表示为传输速度 为115200bit/s,每个脉冲宽度为1s / 115200 = 8.68us
即,收发双方都是按照8.68us的节奏来进行数据的“裁剪”工作,达到“同步”。
2、wiringPi串口接口函数
int serialOpen(char *device, int baud)
device:串口的地址默认一般是"/dev/ttyAMA0"
baud:波特率
返回:正常返回文件描述符,否则返回-1失败。
void serialClose(int fd)
fd:文件描述符 关闭fd关联的串口
void serialPutchar(int fd, unsigned char c)
fd:文件描述符
c:要发送的数据
void serialPuts (int fd, char *s)
fd:文件描述符
s:发送的字符串,字符串要以'\0'结尾
void serialPrintf (int fd, char *message, …)
fd:文件描述符
message:格式化的字符串
int serialDataAvail (int fd)
fd:文件描述符
返回:串口缓存中已经接收的,可读取的字节数,-1代表错误
int serialGetchar (int fd)
fd:文件描述符
返回:读取到的字符
如果串口缓存中没有可用的数据,则会阻塞10秒,如果10后还有没,返回-1
所以,在读取前,做好通过serialDataAvail判断下。
void serialFlush (int fd)
fd:文件描述符
刷新,清空串口缓冲中的所有可用的数据。
3、发送数据测试
#include <stdio.h>
#include <stdlib.h>
#include "wiringPi.h"
#include "wiringSerial.h"
int main(void)
{
//打开串口,设备驱动为/dev/ttyAMA0
int fd = serialOpen("/dev/ttyAMA0", 115200);//波特率
char str[100] = "";
while(1){
//发送0xAA,即0B10101010
serialPutchar(fd, 0xaa);
//每一秒往串口输出helloworld
//serialPuts(fd, "helloworld\n");
//sleep(1);
}
return 0;
}
4、时序分析
按照串口协议,此程序中波特率选择115200,其他没有设置,即默认无奇偶校验,停止位宽度为1,8位有效数据。 开始为起始位为0,有效数据位0B10101010,由于LSB低位在前,因此数据时序就变成01010101倒置,停止位1 因此时序应为0010101011这样的周期时序。
5、使用ttl转usb与计算机进行串口通信,从计算机读取
#include <stdio.h>
#include "wiringPi.h"
#include "wiringSerial.h"
#include <string.h>
int main(void)
{
//打开串口,设备驱动为/dev/ttyAMA0
int fd = serialOpen("/dev/ttyAMA0", 115200);
char str[100] = "";
int idx = 0;
char ch = 0;
while(1){
//由于串口输入serialGetchar有阻塞,因此通过serialDataAvail接口判断缓存中是否有数据写入,再进行读取
if(serialDataAvail(fd) > 0){
char ch = serialGetchar(fd);
str[idx] = ch;
if(ch == '\n')
{
str[idx] = '\0';
printf("%s\n", str);
idx = 0;
}else
{
idx++;
}
}
}
return 0;
}