火龙果(redpitaya)开发板常用接口C语言开发指南(十一)——串口通信详解(持续更新中)
- 串口通信
- 串口及使用模块简介
- red pitaya串口收发红外译码数据
——本人为《火龙果实战指南——搭建基于Zynq处理器的测量仪器与创新实践平台》一书的作者之一,为了便于各位快速上手火龙果开发板,现提供部分实战指南,包含环境配置、源码、效果等,供大家学习交流使用。
Red pitaya开发板设计的初衷是用较低的成本,打造一个开发人员、学生和创客用于测量和控制的工具,以替代数台高价的实验设备。此开发板搭载双核心ARM® Cortex® A9 MCU和FPGA MCU,支持I2C、串口和SPI等数据总线的传输。接下来两节主要介绍如何使用red pitaya开发板板的通信接口进行相关的开发工作。
串口通信
red pitaya开发板实物如下图1所示,其中红色箭头所标注的E2接口为板子带有串口、IIC、SPI的拓展接口。
图1 red pitaya开发板实物
串口及使用模块简介
串行口是计算机中一种常用的接口,具有连接线少,通讯简单的特点,得到广泛的使用。常用的串口接口是 RS-232-C (又称 EIA RS-232-C),它是在 1970 年由美国电子工业协会(EIA)联合贝尔系统、 调制解调器厂家及计算机终端生产厂家共同制定的用于串行通讯的标准。此标准的全名是"数据终端设备(DTE)和数据通讯设备(DCE)之间串行二进制数据交换接口技术标准"该标准规定采用一个 25 个脚的 DB25 连接器,对连接器的每个引脚的信号内容加以规定,还对各种信号的电平加以规定。传输距离在码元畸变小于4% 的情况下,传输电缆长度应为50 英尺。
计算机可以每次传送一个或者多个位(bit)的数据。“串行”指的是每次只传输一位(1bit)数据。当需要通过串行通讯传输一个字(word)的数据时,只能以每次一位的方式接收或者发送。每个位可能是on(1)或者off(0)。很多技术文档中经常用mark表示on,而space表示off。
串行数据的速度通常用每秒传输的字节数bits-per-second(bps)或者波特率(baud)表示。这个值表示的是每秒钟被送出的0和1 的个数。很久以前,300bps就是很快的速度了,而随着科技进步,现在的电脑可以处理高达430,800的RS-232速率。表示波特率的单位还有kpbs和 Mbps,他们之间的关系为1kps=1000bps,1Mbps=1000kbps。一般提到串行设备的时候,通常说可能是某种数据通讯设备-DCE(Data Communications Equipment)或者数据终端设备-DTE(Data Terminal Equipment)。如果需要将两个DTE或者DCE设备连接起来的话,需要适配器或者交叉线缆将信号对交换。
模块结构图如图2所示。首先使用此模块对发射的红外(比如空调遥控器按下开关键)进行解码,解码时不需要发送任何指令,只需要拿起遥控对准模块的接收头按下,这时模块的串口就输出该红外编码。通过程序控制将此解码数据传输到red pitaya开发板。
与此同时,可以将red pitaya开发板收到的编码数据根据一定格式发送出去来远程控制空调的开关,即通过red pitaya开发板发送5个字节的指令,当空调开关按下,red pitaya开发板接收到的数据为(01 03 00),此时调用linux下的串口发射函数发射NEC信号编码为(01 03 00),即:由red pitaya开发板通过串口发射到红外模块的为:{A1,F1,0103,00}。
图 2 串口收发模块结构图
red pitaya串口收发红外译码数据
图3 red pitaya扩展接口示意图
如图3所示,red pitaya开发板的E2上的第7脚和第8脚分别对应ARM Cortex A9的uart Tx和uart Rx。由于板子底层搭建的是纯linux,通过linux下c编程可以控制串口的收发。在这个基础上,配合红外译码模块,可以将译码模块串口输出的红外编码显示在linux系统终端上,并且存储在板子EEPROM中。与此同时,可以根据配合本例程所需的红外译码模块的发射红外功能,通过编程远程遥控家用电器。
要完成此项例程,主要需要保证red pitaya开发板的串口收发功能正常工作:首先使用USB转TTL接口模块,实现red pitaya开发板与电脑的连接。通过串口助手显示red pitaya开发板发送给电脑的数据,并且也可以通过串口助手发送数据至red pitaya开发板。
连接开发板并在项目文件夹redpitaya下创建UART-Pitaya.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 <unistd.h>
#include <string.h>
#define DEVICE "/dev/ttyPS1"
#define S_TIMEOUT 1
int serial_fd = 0;//打开串口并初始化设置
int init_serial(void)
{
serial_fd = open(DEVICE, O_RDWR | O_NOCTTY | O_NDELAY);
if (serial_fd < 0) {
perror("open");
return -1;
}//串口主要设置结构体termios <termios.h>
struct termios options;
options.c_cflag |= (CLOCAL | CREAD); //设置控制模式状态,本地连接,接收能
options.c_cflag &= ~CSIZE; //字符长度,设置数据位之前一定要屏掉这个位
options.c_cflag &= ~CRTSCTS; //无硬件流控
options.c_cflag |= CS8; //8位数据长度
options.c_cflag &= ~CSTOPB; //1位停止位
options.c_iflag |= IGNPAR; //无奇偶检验位
options.c_oflag = 0; //输出模式
options.c_lflag = 0; //不激活终端模式
cfsetospeed(&options, B9600); //设置波特率
tcflush(serial_fd, TCIFLUSH);//溢出数据可以接收,但不读
tcsetattr(serial_fd, TCSANOW, &options);
return 0;
}
unsigned int total_send = 0 ;
int uart_send(int fd, char *data, int datalen)
{
int len = 0;
len = write(fd, data, datalen); //实际写入的长度
if(len == datalen) {
total_send += len ;
printf("total_send is %d\n",total_send);
return len;
} else {
tcflush(fd, TCOFLUSH); //TCOFLUSH刷新写入的数据但不传送
return -1;
}
return 0;
}
unsigned int total_length = 0 ;
int uart_recv(int fd, char *data, int datalen)
{
int len=0, ret = 0,i;
unsigned int data1[] = {0xA1,0xF1,0x01,0x03,0x00};
fd_set fs_read;
struct timeval tv_timeout;
FD_ZERO(&fs_read);
FD_SET(fd, &fs_read);
#ifdef S_TIMEOUT
tv_timeout.tv_sec = (10*20/9600+2);
tv_timeout.tv_usec = 0;
ret = select(fd+1, &fs_read, NULL, NULL, NULL);
#elif
ret = select(fd+1, &fs_read, NULL, NULL, tv_timeout);
#endif
if (FD_ISSET(fd, &fs_read)) {
len = read(fd, data, datalen);
total_length += len ;
printf("receive the data: %x %x %x\n", data[0],data[1],data[2]);
//printf("data: %s",data);
return len;
} else {
perror("select");
return -1;
}
if(data[0] == 01 &&data[1] == 03 && data[2] == 00)
{
uart_send(serial_fd,data1, 11);
printf("send the receive data to turn on the media");
}
return 0;
}
int main(int argc, char **argv)
{
init_serial();
int total_ln,i;
char buf[]="hello world";
unsigned char buf1[200] ;
memset(buf1,0,sizeof(char)*11);
while(1)
{
// uart_send(serial_fd, buf, 11);
// printf("\n");
// sleep(1);
//if(uart_recv(serial_fd, buf1, 11) > 0)
total_ln = uart_recv(serial_fd, buf1, 200);
printf("send the receive data to turn on the media");
memset(buf1,0,sizeof(char)*200);
}
close(serial_fd);
return 0;
}
编译参考命令:
cd /hmoe/UART-Pitaya
gcc –o UART-Pitaya UART-Pitaya.c
./ UART-Pitaya
此时程序开始运行,如图4所示将红外译码模块与Redpitay板连接后按下空调遥控器的开关键,在Redpitaya终端输出对于此按键红外对应的16进制的数据信息。
图4 串口程序运行效果图