uart应用编程

简介: uart应用编程
/**@file      main.
 * @brief       串口应用编程测试
 * @details
 **********************************************************************************
 * @par 修改日志:
 **********************************************************************************
 */
/* 包含的头文件 */
#include <stdio.h>        //标准输入输出,如printf、scanf以及文件操作
#include <stdlib.h>        //标准库头文件,定义了五种类型、一些宏和通用工具函数
#include <unistd.h>        //定义 read write close lseek 等Unix标准函数
#include <sys/types.h>    //定义数据类型,如 ssiz e_t off_t 等
#include <sys/stat.h>    //文件状态
#include <fcntl.h>        //文件控制定义
#include <termios.h>    //终端I/O
#include <errno.h>        //与全局变量 errno 相关的定义
#include <getopt.h>        //处理命令行参数
#include <string.h>        //字符串操作
#include <time.h>        //时间
#include <sys/select.h>    //select函数
#define DEV_NAME    "/dev/ttyAMA1"    ///< 串口设备
/**@brief   设置串口参数:波特率,数据位,停止位和效验位
 * @param[in]  fd         类型  int      打开的串口文件句柄
 * @param[in]  nSpeed     类型  int     波特率
 * @param[in]  nBits     类型  int     数据位   取值 为 7 或者8
 * @param[in]  nParity     类型  int     停止位   取值为 1 或者2
 * @param[in]  nStop      类型  int      效验类型 取值为N,E,O,,S
 * @return     返回设置结果
 * - 0         设置成功
 * - -1     设置失败
 */
int setOpt(int fd, int nSpeed, int nBits, int nParity, int nStop)
{
    struct termios newtio, oldtio;
    // 保存测试现有串口参数设置,在这里如果串口号等出错,会有相关的出错信息
    if (tcgetattr(fd, &oldtio) != 0)
    {
        perror("SetupSerial 1");
        return -1;
    }
    bzero(&newtio, sizeof(newtio));        //新termios参数清零
    newtio.c_cflag |= CLOCAL | CREAD;    //CLOCAL--忽略 modem 控制线,本地连线, 不具数据机控制功能, CREAD--使能接收标志
    // 设置数据位数
    newtio.c_cflag &= ~CSIZE;    //清数据位标志
    switch (nBits)
    {
        case 7:
            newtio.c_cflag |= CS7;
        break;
        case 8:
            newtio.c_cflag |= CS8;
        break;
        default:
            fprintf(stderr, "Unsupported data size\n");
            return -1;
    }
    // 设置校验位
    switch (nParity)
    {
        case 'o':
        case 'O':                     //奇校验
            newtio.c_cflag |= PARENB;
            newtio.c_cflag |= PARODD;
            newtio.c_iflag |= (INPCK | ISTRIP);
            break;
        case 'e':
        case 'E':                     //偶校验
            newtio.c_iflag |= (INPCK | ISTRIP);
            newtio.c_cflag |= PARENB;
            newtio.c_cflag &= ~PARODD;
            break;
        case 'n':
        case 'N':                    //无校验
            newtio.c_cflag &= ~PARENB;
      newtio.c_iflag |= IXOFF; //mu add
            newtio.c_lflag &= ~IEXTEN ;//mu add
            break;
        default:
            fprintf(stderr, "Unsupported parity\n");
            return -1;
    }
    // 设置停止位
    switch (nStop)
    {
        case 1:
            newtio.c_cflag &= ~CSTOPB;
        break;
        case 2:
            newtio.c_cflag |= CSTOPB;
        break;
        default:
            fprintf(stderr,"Unsupported stop bits\n");
            return -1;
    }
    // 设置波特率 2400/4800/9600/19200/38400/57600/115200/230400
    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 19200:
            cfsetispeed(&newtio, B19200);
            cfsetospeed(&newtio, B19200);
            break;
        case 38400:
            cfsetispeed(&newtio, B38400);
            cfsetospeed(&newtio, B38400);
            break;
        case 57600:
            cfsetispeed(&newtio, B57600);
            cfsetospeed(&newtio, B57600);
            break;
        case 115200:
            cfsetispeed(&newtio, B115200);
            cfsetospeed(&newtio, B115200);
            break;
        case 230400:
            cfsetispeed(&newtio, B230400);
            cfsetospeed(&newtio, B230400);
            break;
        default:
            printf("\tSorry, Unsupported baud rate, set default 9600!\n\n");
            cfsetispeed(&newtio, B9600);
            cfsetospeed(&newtio, B9600);
            break;
    }
    // 设置read读取最小字节数和超时时间
    newtio.c_cc[VTIME] = 0;     // 读取一个字符等待1*(1/10)s
    newtio.c_cc[VMIN] = 1;        // 读取字符的最少个数为1
      tcflush(fd,TCIFLUSH);         //清空缓冲区
      if (tcsetattr(fd, TCSANOW, &newtio) != 0)    //激活新设置
      {
        perror("SetupSerial 3");
          return -1;
     }
      printf("Serial set done!\n");
    return 0;
}
/**@brief 串口读取函数
 * @param[in]  fd         打开的串口文件句柄
 * @param[in]  *rcv_buf 接收缓存指针
 * @param[in]  data_len    要读取数据长度
 * @param[in]  timeout     接收等待超时时间,单位ms
 * @return     返回设置结果
 * - >0      设置成功
 * - 其他      读取超时或错误
 */
int UART_Recv(int fd, char *rcv_buf, int data_len, int timeout)
{
    int len, fs_sel;
    fd_set fs_read;
    struct timeval time;
    time.tv_sec = timeout / 1000;              //set the rcv wait time
    time.tv_usec = timeout % 1000 * 1000;    //100000us = 0.1s
    FD_ZERO(&fs_read);        //每次循环都要清空集合,否则不能检测描述符变化
    FD_SET(fd, &fs_read);    //添加描述符
    // 超时等待读变化,>0:就绪描述字的正数目, -1:出错, 0 :超时
    fs_sel = select(fd + 1, &fs_read, NULL, NULL, &time);
    //printf("fs_sel = %d\n", fs_sel);
    if(fs_sel)
    {
        len = read(fd, rcv_buf, data_len);
        return len;
    }
    else
    {
//        printf("Sorry,I am wrong!");
        return -1;
    }
}
/**@brief 串口发送函数
 * @param[in]  fd            打开的串口文件句柄
 * @param[in]  *send_buf     发送数据指针
 * @param[in]  data_len     发送数据长度
 * @return     返回结果
 * - data_len    成功
 * - -1            失败
 */
int UART_Send(int fd, char *send_buf, int data_len)
{
    ssize_t ret = 0;
    ret = write(fd, send_buf, data_len);
    if (ret == data_len)
    {
       // printf("send data is %#x\r\n", send_buf[0]);
        return ret;
    }
    else
    {
        printf("write device error\n");
        tcflush(fd,TCOFLUSH);
        return -1;
    }
}
/**@fn main
 * @brief main入口函数
 */
int main (int argc, char *argv[])
{
    int fdSerial;
    // 打开串口设备
    fdSerial = open(DEV_NAME, O_RDWR | O_NOCTTY | O_NDELAY);
    if(fdSerial < 0)
    {
        perror(DEV_NAME);
        return -1;
    }
    // 设置串口阻塞, 0:阻塞, FNDELAY:非阻塞
    if (fcntl(fdSerial, F_SETFL, 0) < 0)    //阻塞,即使前面在open串口设备时设置的是非阻塞的
    {
        printf("fcntl failed!\n");
    }
    else
    {
//        printf("fcntl=%d\n", fcntl(fdSerial, F_SETFL, 0));
    }
    if (isatty(fdSerial) == 0)
    {
        printf("standard input is not a terminal device\n");
        close(fdSerial);
        return -1;
    }
    else
    {
  //      printf("is a tty success!\n");
//  printf("tty name is %s \n", ttyname(fdSerial));
    }
  //  printf("fd-open=%d\n", fdSerial);
    // 设置串口参数
    if (setOpt(fdSerial, 115200, 8, 'N', 1)== -1)    //设置8位数据位、1位停止位、无校验
    { 
        fprintf(stderr, "Set opt Error\n");
        close(fdSerial);
        exit(1);
    }
    tcflush(fdSerial, TCIOFLUSH);    //清掉串口缓存
    fcntl(fdSerial, F_SETFL, 0);    //串口阻塞
    char rcv_buf[16];
    int len;
    char send_buf[2] = {0x55,0};
    unsigned int current = 0;
    unsigned int voltage = 0;
    while(1)    //循环读取数据
    {
  memset(rcv_buf, 0, sizeof(rcv_buf));
  UART_Send(fdSerial, send_buf, 1);
        len = UART_Recv(fdSerial, rcv_buf, 16, 5000);
        if(len > 0)
        {
      current = rcv_buf[0] + ((rcv_buf[1] & 0x0f) << 8) ;  
      printf("#current channel:     %.3f A \n", current*3.3/(4096*200*0.000246 ));
      voltage = rcv_buf[2] + ((rcv_buf[3] & 0x0f) << 8);
      printf("#0.8v channel volage: %.3f V \n", voltage*3.3/4096);
      voltage = rcv_buf[4] + ((rcv_buf[5] & 0x0f) << 8);
      printf("#0.9v channel volage: %.3f V \n", voltage*3.3/4096);
      voltage = rcv_buf[6] + ((rcv_buf[7] & 0x0f) << 8);
      printf("#1.2v channel volage: %.3f V \n", voltage*3.3/4096);  
      voltage = rcv_buf[8] + ((rcv_buf[9] & 0x0f) << 8);
      printf("#1.5v channel volage: %.3f V \n", voltage*3.3/4096);
     voltage = rcv_buf[10] + ((rcv_buf[11] & 0x0f) << 8);
     printf("#1.8v channel volage: %.3f V \n", voltage*3.3/4096);
      voltage = rcv_buf[12] + ((rcv_buf[13] & 0x0f) << 8);
      printf("#2.5v channel volage: %.3f V \n", voltage*3.3*2/4096);
      voltage = rcv_buf[14] + ((rcv_buf[15] & 0x0f) << 8);
      printf("#3.3v channel volage: %.3f V \n\n", voltage*3.3*2/4096);
        }
        else
        {
            printf("cannot receive data\n");
        }
  sleep(2);    //休眠2s
    }
    close(fdSerial);
    return 0;
}


uart的属性一定要先清零在配置。别的没什么重要的。

bzero(&newtio, sizeof(newtio));        //新termios参数清零

我的串口是采集电压电流的解析。执行情况:


微信图片_20230118095308.png

目录
相关文章
|
7月前
|
存储 缓存 芯片
STM32标准库SPI通信协议与W25Q64-2
STM32标准库SPI通信协议与W25Q64
|
7月前
|
存储 芯片
STM32标准库SPI通信协议与W25Q64-1
STM32标准库SPI通信协议与W25Q64
|
7月前
|
安全 Linux 数据安全/隐私保护
【SPI协议】了解ARM平台上的SPI的基本应用
【SPI协议】了解ARM平台上的SPI的基本应用
655 0
|
Linux API 芯片
USB2S可编程USB转串口适配器开发原理的通讯协议
USB2S可编程USB转串口适配器基于FTDI FT2232H芯片设计,对多种通讯协议的支持,包括UART,I2C,SMBus,1-Wire,SPI,CAN和PWM等。
USB2S可编程USB转串口适配器开发原理的通讯协议
|
XML 测试技术 网络安全
开发工具:USB转IIC/I2C/SPI/UART适配器模块可编程开发板
总的思路是通过USB或者UART接口发送一些协议字符串,由模块转换成上面几种接口的硬件时序电信号,实现与这几种接口芯片、设备的快速测试。 首先声明一下,大家都是搞硬件开发的,这几种接口当然是很简单的事,但有些时候对于一个新的设备或者芯片的测试,有个现成的工具当然更顺手,节省时间,也更可靠嘛。
|
存储 安全 定位技术
串口,IIC,SPI,USB等总线叙述
串口,IIC,SPI,USB等总线叙述
210 0
|
XML 测试技术 网络安全
开发调试工具:可编程USB转IIC/I2C/SPI/UART适配器模块开发板
发个方便测试I2C、SPI、1Wire接口的工具模块 总的思路是通过USB或者UART接口发送一些协议字符串,由模块转换成上面几种接口的硬件时序电信号,实现与这几种接口芯片、设备的快速测试。
STM32使用HAL库实现modbus的简单通讯
STM32使用HAL库实现modbus的简单通讯
328 0
|
存储 Ubuntu Linux
UART子系统(五) 串口应用编程之回环(下)
UART子系统(五) 串口应用编程之回环
581 1
UART子系统(五) 串口应用编程之回环(下)