串口的工作原理
就是通过直接连接在两台设备间的线发送和接收数据。最少三根线RX、TX、GND。常见的还有RS232有9根线
串口应用程序
操作串口的方法和文件十分类似。
#include <stdio.h> /*标准输入输出定义*/
#include <stdlib.h> /*标准函数库定义*/
#include <unistd.h> /*Unix 标准函数定义*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h> /*文件控制定义*/
#include <termios.h> /*PPSIX 终端控制定义*/
#include <errno.h> /*错误号定义*/
int main()
{
int fd;
fd = open( "/dev/ttyS0", O_RDWR); // 使用读写方式打开串口
if (-1 == fd){
perror("open ttyS0");
return 0;
}
printf("Open ttyS0 OK!\n");
close(fd); // 关闭串口
return 0;
}
需要注意的是,这个程序要在编译后用ROOT权限执行。目前就是打开看看,无特殊操作
串口的属性设置
Linux常用termios结构储存串口参数,定义如下
每个成员都有多个选项值不一一介绍了…太多了
同时termios.h为termios结构提供了一组设置的函数,定义如下:
tcgetattr()函数读取串口的参数设置,tcsetattr()函数用于指定串口参数,其他的都是一些辅助函数。
tcsendbreak()函数传输连续的0值比特流。
tcdrain()函数会等待直到所有写入fd引用对象的输出都被送走。
tcflush()函数丢弃要写入引用对象但未传输的数据,或收到但未读取的书。
tcflow()挂起fd引用对象上的数据传输或接收。
cfmakeraw()设置终端属性为原始的数据方式。
cfgetispeed()和cfgetospeed()用来得到串口的输入和输出速率。
除了cfgetispeed()和cfgetospeed()其他函数返回值0位成功,-1为失败
和windows的串口通讯
配置是19200 N 8 1
#include <stdio.h> /*标准输入输出定义*/
#include <stdlib.h> /*标准函数库定义*/
#include <unistd.h> /*Unix 标准函数定义*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h> /*文件控制定义*/
#include <termios.h> /*PPSIX 终端控制定义*/
#include <errno.h> /*错误号定义*/
#define STTY_DEV "/dev/ttyS0"
#define BUFF_SIZE 512
int main()
{
int stty_fd, n;
char buffer[BUFF_SIZE];
struct termios opt;
/* 打开串口设备 */
stty_fd = open(STTY_DEV, O_RDWR);
if (-1==stty_fd) {
perror("open device");
return 0;
}
printf("Open device success, waiting user input ...\n");
/* 取得当前串口配置 */
tcgetattr(stty_fd, &opt);
tcflush(stty_fd, TCIOFLUSH);
/* 设置波特率 - 19200bps */
cfsetispeed(&opt, B19200);
cfsetospeed(&opt, B19200);
/* 设置数据位 - 8位数据位 */
opt.c_cflag &= ~CSIZE;
opt.c_cflag |= CS8;
/* 设置奇偶位 - 无奇偶校验 */
opt.c_cflag &= ~PARENB;
opt.c_iflag &= ~INPCK;
/* 设置停止位 - 1位停止位 */
opt.c_cflag &= ~CSTOPB;
/* 设置超时时间 - 15秒 */
opt.c_cc[VTIME] = 150;
opt.c_cc[VMIN] = 0;
/* 设置写入设备 */
if (0!=tcsetattr(stty_fd, TCSANOW, &opt)) {
perror("set baudrate");
return 0;
}
tcflush(stty_fd, TCIOFLUSH);
/* 读取数据,直到接收到'quit'字符串退出 */
while(1) {
n = read(stty_fd, buffer, BUFF_SIZE);
if (n<=0) {
perror("read data");
break;
}
buffer[n] = '\0';
printf("%s", buffer);
if (0==strncmp(buffer, "quit", 4)) {
printf("user send quit!\n");
break;
}
}
printf("Program will exit!\n");
close(stty_fd);
}
Windows 用个串口工具发送,Linux这段就会接收(小提示,需要用root权限)
后面还有高级操作…就放出来看看
手机和电脑连接发短消息
/* at_test.c - gcc -o at_test at_test.c */
#include <stdio.h> /*标准输入输出定义*/
#include <stdlib.h> /*标准函数库定义*/
#include <unistd.h> /*Unix 标准函数定义*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h> /*文件控制定义*/
#include <termios.h> /*PPSIX 终端控制定义*/
#include <errno.h> /*错误号定义*/
#include <iconv.h>
#define STTY_DEV "/dev/ttyS0"
#define BUFF_SIZE 512
int SetOption(int fd)
{
struct termios opt;
/* 取得当前串口配置 */
tcgetattr(fd, &opt);
tcflush(fd, TCIOFLUSH);
/* 设置波特率 - 19200bps */
cfsetispeed(&opt, B19200);
cfsetospeed(&opt, B19200);
/* 设置数据位 - 8位数据位 */
opt.c_cflag &= ~CSIZE;
opt.c_cflag |= CS8;
/* 设置奇偶位 - 无奇偶校验 */
opt.c_cflag &= ~PARENB;
opt.c_iflag &= ~INPCK;
/* 设置停止位 - 1位停止位 */
opt.c_cflag &= ~CSTOPB;
/* 设置超时时间 - 15秒 */
opt.c_cc[VTIME] = 150;
opt.c_cc[VMIN] = 0;
/* 设置写入设备 */
if (0!=tcsetattr(fd, TCSANOW, &opt)) {
perror("set baudrate");
return -1;
}
tcflush(fd, TCIOFLUSH);
return 0;
}
int main()
{
int stty_fd, n;
iconv_t cd;
char buffer[BUFF_SIZE];
char phone[20] = "+8618912345678"; // 定义手机号码
char sms_number[20] = "+8613800200500"; // 定义短消息中心号码
char sms_gb2312[140] = "工作愉快!"; // 定义短消息内容哦
char sms_utf8[140];
char *sms_in = sms_gb2312;
char *sms_out = sms_utf8;
int str_len, i, tmp;
int gb2312_len, utf8_len;
/* 打开串口设备 */
stty_fd = open(STTY_DEV, O_RDWR);
if (-1==stty_fd) {
perror("open device");
return 0;
}
printf("Open device success!\n");
/* 设置串口参数 */
if (0!=SetOption(stty_fd)) {
close(stty_fd);
return 0;
}
/* 转换电话号 */
if (phone[0] = '+') {
// 去掉号码开头的'+'
for ( i=0; i<strlen(phone)-1; i++ )
phone[i] = phone[i+1];
}
phone[i] = '\0';
str_len = strlen(phone);
if ((strlen(phone)%2)!=0) {
// 如果号码长度是奇数,在后面加字符'F'
phone[str_len] = 'F';
phone[str_len+1] = '\0';
}
for (i=0;i<strlen(phone);i+=2) {
//把号码的奇偶位调换
tmp = phone[i];
phone[i] = phone[i+1];
phone[i+1] = tmp;
}
/* 转换短消息中心号码 */
if (sms_number[0] = '+') {
// 去掉号码开头的'+'
for ( i=0; i<strlen(sms_number)-1; i++ )
sms_number[i] = sms_number[i+1];
}
sms_number[i] = '\0';
str_len = strlen(sms_number);
if ((strlen(sms_number)%2)!=0) {
// 如果号码长度是奇数,在后面加字符'F'
sms_number[str_len] = 'F';
sms_number[str_len+1] = '\0';
}
for (i=0;i<strlen(sms_number);i+=2) {
//把号码的奇偶位调换
tmp = sms_number[i];
sms_number[i] = sms_number[i+1];
sms_number[i+1] = tmp;
}
str_len = strlen(sms_number);
for (i=strlen(sms_number)+2;i!=0;i--) // 所有的字符向后移动两个字节
sms_number[i] = sms_number[i-2];
sms_number[str_len+3] = '\0';
strncpy(sms_number, "91", 2); // 开头写入字符串"91"
tmp = strlen(sms_number)/2; // 计算字符串长度
str_len = strlen(sms_number);
for (i=strlen(sms_number)+2;i!=0;i--) // 所有的字符向后移动两个字节
sms_number[i] = sms_number[i-2];
sms_number[str_len+3] = '\0';
sms_number[0] = (char)(tmp/10) + 0x30; // 字符串长度转换为字符类型写入开头
sms_number[1] = (char)(tmp%10) + 0x30;
/* 转换短消息内容 */
cd = iconv_open("utf-8", "gb2312"); //设置转换类型"gb2312"==>"utf-8"
if (0==cd) {
perror("create iconv handle!");
close(stty_fd);
return 0;
}
gb2312_len = strlen(sms_gb2312); // 输入字符串的长度
utf8_len = 140;
if (-1==iconv(cd, &sms_in, &gb2312_len,
&sms_out, &utf8_len)) {
// 转换字符为Unicode编码
perror("convert code");
close(stty_fd);
return 0;
}
iconv_close(cd);
/* 设置使用PDU模式 */
strcpy(buffer, "AT+CMGF=0\n");
write(stty_fd, buffer, strlen(buffer)); // 写入配置命令
n = read(stty_fd, buffer, BUFF_SIZE);
if (n<=0) {
perror("set pdu mode");
close(stty_fd);
return 0;
}
if (0!=strncmp(buffer, "OK", 2)) {
// 判断命令是否执行成功
perror("set pdu mode");
close(stty_fd);
return 0;
}
/* 发送消息 */
sprintf(buffer, "AT+CMGS=%d\n", utf8_len); // 写入发送消息命令
write(stty_fd, buffer, strlen(buffer));
write(stty_fd, sms_utf8, utf8_len); // 写入消息内容
printf("Send message OK!\n");
close(stty_fd);
}
其中用到了PDU编码,AT指令等…