控制字符设备
字符设备是指在I/O传输过程中以字符为单位进行传输的设备,例如键盘,打印机等。在UNIX系统中,字符设备以特别文件方式在文件目录树中占据位置并拥有相应的结点。
(一)、控制LED亮灭
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
//CMD 0:灭 1:亮
//io为0的LED靠近蜂鸣器
//io为1的LED靠近独立按键
int main(int argc, char* argv[]){
int fd;
char *leds="/dev/leds";
printf("argv1 is cmd; argv2 is io\n");
if(atoi(argv[1])>1){
printf("argv1 is 0 or 1\n");
exit(1);
}
if(atoi(argv[2])>1){
printf("argv2 is 0 or 1\n");
exit(1);
}
//文件可读写 不作为进程的控制终端 不堵塞
if((fd = open(leds, O_RDWR|O_NOCTTY|O_NDELAY))<0){
printf("open %s failed\n", leds);
}
else{
ioctl(fd, atoi(argv[1]), atoi(argv[2]));
printf("ioctl %s success\n", leds);
}
close(fd);
return(0);
}
函数说明:
-
atoi()——ascii码转换为整型函数 ascii to integer
#include <stdlib.h>
int atoi(const char *nptr); -
设备IO控制函数
#include <sys/ioctl.h>
int ioctl(int d, int request, …);
使用交叉编译链编译完之后再开发板上输入
led 0 0 代表熄灭第0盏灯
led 1 0 代表点亮第0盏灯
led 0 1 代表熄灭第1盏灯
led 1 1 代表点亮第1盏灯
二、控制串口
(一)、文件开机启动
修改文件/etc/init.d/rcS,添加要执行的文件路径并在后面加上&。
重启一下
(二)、串口初始化函数
串口初始化步骤:
- 读取参数
- 修改参数
- 配置参数
可通过命令“man 3 tcgetattr”获取它以及其他函数的用法。
1、读取指定终端的属性
int tcgetattr(int fd, struct termios *termios_p);
fd就是打开文件返回的文件描述符。
termios结构体的定义如下。
在source insight里面可以看到:
在linux下也可以看到:
tcflag_t c_iflag; /\* input modes 输入模式标志位\*/
tcflag_t c_oflag; /\* output modes 输出模式标志位\*/
tcflag_t c_cflag; /\* control modes 控制模式标志位\*/
tcflag_t c_lflag; /\* local modes 本地模式标志位\*/
cc_t c_cc[NCCS]; /\* special characters 特殊描述符\*/
2、获取当前波特率函数
speed_t cfgetispeed(const struct termios *termios_p);
speed_t cfgetospeed(const struct termios *termios_p);
参数说明:
termios_p:结构体如上所示,包含终端的相关信息。
3、设置波特率函数
int cfsetispeed(struct termios *termios_p, speed_t speed);
int cfsetospeed(struct termios *termios_p, speed_t speed);
int cfsetspeed(struct termios *termios_p, speed_t speed);
参数说明:
termios_p:结构体如上所示,包含终端的相关信息,表示在旧的参数基础上修改后的新参数。
speed:波特率可选参数如下所示。(baud rate xxx)
B0
B50
B75
B110
B134
B150
B200
B300
B600
B1200
B1800
B2400
B4800
B9600
B19200
B38400
B57600
B115200
B230400
4、刷新串口数据缓冲区函数
int tcflush(int fd, int queue_selector);
参数说明:
fd:open返回的文件句柄。
queue_selector:用于选择刷新缓冲区(队列)中的哪些数据,具体参数说明如下。
TCIFLUSH
flushes data received but not read. 刷新已接收(至缓冲区)但未读取的数据TCOFLUSH
flushes data written but not transmitted.刷新已写入(至缓冲区)但未发送的数据TCIOFLUSH
flushes both data received but not read, and data written but not transmitted.同时刷新已接收(至缓冲区)但未读取的数据和已写入(至缓冲区)但未发送的数据。
5、设置串口参数函数
int tcsetattr(int fd, int optional_actions, const struct termios *termios_p);
fd:open返回的文件句柄。
optional_actions:用于选择参数生效的时间。
TCSANOW
the change occurs immediately.不等待数据传输完毕就立即改变属性。TCSADRAIN
the change occurs after all output written to fd has been trans‐mitted. This function should be used when changing parameters that affect output.等待所有数据传输结束才改变属性。TCSAFLUSH
the change occurs after all output written to the object referred by fd has been transmitted, and all input that has been received but not read will be discarded before the change is made.
将所有输出数据写入到fd之后才修改参数,并在更改之前舍弃所有已接收但未读取的输入数据。
termios_p:表示在旧的参数基础上修改后的新参数。
(三)、串口输出函数
函数间隔1s输出10次“Hello, Seanoy”
//标准库
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//文件IO操作
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
//串口操作
#include <termios.h>
#include <unistd.h>
int uart_init(int,int,int,char,int);
int main(int argc, char* argvp[])
{
int fd, wr_return, i=10;
char *uart3 = "/dev/ttySAC3";//串口3对应路径
char *buffer = "Hello Seanoy!\n";
printf("\r\n uart3 write test start\r\n");
if((fd = open(uart3, O_RDWR|O_NOCTTY|O_NDELAY))<0){//打开文件
printf("open %s failed\r\n", uart3);
}
else{
printf("open %s succeed\r\n", uart3);
uart_init(fd, 115200, 8, 'N', 1);//串口初始化
while(i--)
{
wr_return = write(fd, buffer, strlen(buffer));
if(wr_return<0)//发送10次信息
printf("uart3 write failed\r\n");
else
printf("uart3 write return %d\r\n", wr_return);//返回写数据的长度
sleep(1);//休眠1s
}
}
close(fd);//关闭文件
return 0;
}
//对串口的文件句柄 配置波特率 数据位 奇偶检验位 停止位
int uart_init(int fd, int nSpeed, int nBits, char nEvent, int nStop){
struct termios newtio, oldtio;
if( tcgetattr(fd, &oldtio) !=0 ){
perror("SetupSerial 1");
return -1;
}
bzero( &newtio, sizeof(newtio));
newtio.c_cflag |= CLOCAL | CREAD;
newtio.c_cflag &= ~CSIZE;
switch( nSpeed )
{
case 2400:
cfsetispeed(&newtio, B2400);
cfsetospeed(&newtio, B2400);
break;
case 4800:
cfsetispeed(&newtio, B4800);
cfsetospeed(&newtio, B4800);
break;
case 9600:
cfsetispeed(&newtio, B9600);
cfsetospeed(&newtio, B9600);
break;
case 115200:
cfsetispeed(&newtio, B115200);
cfsetospeed(&newtio, B115200);
break;
case 460800:
cfsetispeed(&newtio, B460800);
cfsetospeed(&newtio, B460800);
break;
default:
cfsetispeed(&newtio, B9600);
cfsetospeed(&newtio, B9600);
break;
}
switch( nBits ){
case 7:
newtio.c_cflag |= CS7;
break;
case 8:
newtio.c_cflag |= CS8;
break;
default:
break;
}
switch( nEvent )
{
case 'O':
newtio.c_cflag |= PARENB;//使能校验位
newtio.c_cflag |= PARODD;//使能奇校验位
newtio.c_iflag |= (INPCK | ISTRIP);
break;
case 'E':
newtio.c_cflag |= PARENB;//使能校验位
newtio.c_cflag &= ~PARODD;//使能偶校验位
newtio.c_iflag |= (INPCK | ISTRIP);
break;
case 'N':
newtio.c_cflag &= ~PARENB;//失能校验位
break;
}
if( nStop == 1 )
newtio.c_cflag &= ~CSTOPB;
else if( nStop == 2 )
newtio.c_cflag |= CSTOPB;
newtio.c_cc[VTIME] = 0;
newtio.c_cc[VMIN] = 0;
tcflush(fd,TCIFLUSH);
if((tcsetattr(fd,TCSANOW,&newtio))!=0)
{
perror("com set error");
return -1;
}
return 0;
}