嵌入式Linux学习(第四天学习一)——串口通讯

串口的工作原理

就是通过直接连接在两台设备间的线发送和接收数据。最少三根线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指令等…

猜你喜欢

转载自blog.csdn.net/u010594449/article/details/105724790