本帖最后由 dongwb001 于 2019-8-25 21:58 编辑
串口通信电路板接收电脑的数据都是正常的,发送不正常,代码如下
配置相关的#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 <string.h>
#include <assert.h>
#include "uart.h"
static int fd;
/*******************************************************************
* 名称: UART0_Open
* 功能: 打开串口并返回串口设备文件描述
* 入口参数: fd :文件描述符 port :串口号(ttyS0,ttyS1,ttyS2)
* 出口参数: 正确返回为1,错误返回为0
*******************************************************************/
int uart_open(int fd,const char *pathname)
{
assert(pathname);
fd = open(pathname,O_RDWR | O_NOCTTY | O_NONBLOCK | O_NDELAY);
if(fd == -1)
{
perror("Open UART failed!");
return FALSE;
}
/*恢复串口为阻塞状态,阻塞状态即在读写串口的过程中,
* 如果没有读取到足够的数据,则会一直等待,直到出现对应的数据为止,可以使用select绕过阻塞
*非阻塞:fcntl(fd,F_SETFL,FNDELAY)
*/
if(fcntl(fd, F_SETFL, 0) < 0)
{
printf("fcntl failed!\n");
return FALSE;
}
else
{
printf("fcntl=%d\n",fcntl(fd, F_SETFL,0));
}
//测试是否为终端设备
if(0 == isatty(STDIN_FILENO))
{
printf("standard input is not a terminal device\n");
return FALSE;
}
else
{
printf("isatty success!\n");
}
printf("fd->open=%d\n",fd);
return fd;
}
/*******************************************************************
* 名称: uart_close
* 功能: 关闭串口并返回串口设备文件描述
* 入口参数: fd :文件描述符 port :串口号(ttyS0,ttyS1,ttyS2)
* 出口参数: void
*******************************************************************/
void uart_close(int fd)
{
close(fd);
}
/*******************************************************************
* 名称: uart_set
* 功能: 设置串口数据位,停止位和效验位
* 入口参数: fd 串口文件描述符
* speed 串口速度
* flow_ctrl 数据流控制
* databits 数据位 取值为 7 或者8
* stopbits 停止位 取值为 1 或者2
* parity 效验类型 取值为N,E,O,,S
*出口参数: 正确返回为1,错误返回为0
*******************************************************************/
int uart_set(int fd,int baude,int c_flow,int bits,char parity,int stop)
{
struct termios options;
/*tcgetattr(fd,&options)得到与fd指向对象的相关参数,并将它们保存于options,
*该函数还可以测试配置是否正确,该串口是否可用等。若调用成功,函数返回值为0,若调用失败,函数返回值为1.
*/
if(tcgetattr(fd,&options) < 0)
{
perror("tcgetattr error");
return -1;
}
//设置串口输入波特率和输出波特率
switch(baude)
{
case 115200:
cfsetispeed(&options, B115200);
cfsetospeed(&options, B115200);
printf("enter bande 115200\n");
break;
case 9600:
cfsetispeed(&options, B9600);
cfsetospeed(&options, B9600);
printf("enter bande 9600\n");
break;
default:
printf("enter bande Error \n");
break;
}
/*设置控制模式*/
options.c_cflag |= CLOCAL;//保证程序不占用串口
options.c_cflag |= CREAD;//保证程序可以从串口中读取数据
/*设置数据流控制*/
switch(c_flow)
{
case 0://不进行流控制
options.c_cflag &= ~CRTSCTS;
printf("no c_flow \n");
break;
case 1://进行硬件流控制
options.c_cflag |= CRTSCTS;
break;
case 2://进行软件流控制
options.c_cflag |= IXON|IXOFF|IXANY;
break;
default:
fprintf(stderr,"Unkown c_flow!\n");
return -1;
}
/*设置数据位*/
switch(bits)
{
case 5:
options.c_cflag &= ~CSIZE;//屏蔽其它标志位
options.c_cflag |= CS5;
break;
case 6:
options.c_cflag &= ~CSIZE;//屏蔽其它标志位
options.c_cflag |= CS6;
break;
case 7:
options.c_cflag &= ~CSIZE;//屏蔽其它标志位
options.c_cflag |= CS7;
break;
case 8:
options.c_cflag &= ~CSIZE;//屏蔽其它标志位
options.c_cflag |= CS8;
printf("CS8 \n");
break;
default:
fprintf(stderr,"Unkown bits!\n");
return -1;
}
/*设置校验位*/
switch(parity)
{
/*无奇偶校验位*/
case 'n':
case 'N':
options.c_cflag &= ~PARENB;//PARENB:产生奇偶位,执行奇偶校验
options.c_cflag &= ~INPCK;//INPCK:使奇偶校验起作用
fprintf(stderr,"parity n \n");
break;
/*设为空格,即停止位为2位*/
case 's':
case 'S':
options.c_cflag &= ~PARENB;//PARENB:产生奇偶位,执行奇偶校验
options.c_cflag &= ~CSTOPB;//CSTOPB:使用两位停止位
break;
/*设置奇校验*/
case 'o':
case 'O':
options.c_cflag |= PARENB;//PARENB:产生奇偶位,执行奇偶校验
options.c_cflag |= PARODD;//PARODD:若设置则为奇校验,否则为偶校验
options.c_cflag |= INPCK;//INPCK:使奇偶校验起作用
options.c_cflag |= ISTRIP;//ISTRIP:若设置则有效输入数字被剥离7个字节,否则保留全部8位
break;
/*设置偶校验*/
case 'e':
case 'E':
options.c_cflag |= PARENB;//PARENB:产生奇偶位,执行奇偶校验
options.c_cflag &= ~PARODD;//PARODD:若设置则为奇校验,否则为偶校验
options.c_cflag |= INPCK;//INPCK:使奇偶校验起作用
options.c_cflag |= ISTRIP;//ISTRIP:若设置则有效输入数字被剥离7个字节,否则保留全部8位
break;
default:
fprintf(stderr,"Unkown parity!\n");
return -1;
}
/*设置停止位*/
switch(stop)
{
case 1:
options.c_cflag &= ~CSTOPB;//CSTOPB:使用两位停止位
fprintf(stderr,"stop 1 \n");
break;
case 2:
options.c_cflag |= CSTOPB;//CSTOPB:使用两位停止位
break;
default:
fprintf(stderr,"Unkown stop!\n");
return -1;
}
/*设置输出模式为原始输出*/
options.c_oflag &= ~OPOST;//OPOST:若设置则按定义的输出处理,否则所有c_oflag失效
options.c_oflag &= ~(ONLCR|OCRNL);
/*设置本地模式为原始模式*/
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
// options.c_lflag &= ~(ISIG | ICANON);
options.c_iflag &=~(ICRNL|INLCR|BRKINT|IXON|IXOFF|IXANY);
/*
*ICANON:允许规范模式进行输入处理
*ECHO:允许输入字符的本地回显
*ECHOE:在接收EPASE时执行Backspace,Space,Backspace组合
*ISIG:允许信号
*/
/*使用二进制,删除不必要的控制符号*/
// options.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON | IGNCR);
/*设置等待时间和最小接受字符*/
options.c_cc[VTIME] = 0;//可以在select中设置
options.c_cc[VMIN] = 1;//最少读取一个字符
/*如果发生数据溢出,只接受数据,但是不进行读操作*/
tcflush(fd,TCIFLUSH);
/*激活配置*/
if(tcsetattr(fd,TCSANOW,&options) < 0)
{
perror("tcsetattr failed");
return -1;
}
return TRUE;
}
/*******************************************************************
* 名称: uart_init()
* 功能: 串口初始化
* 入口参数: fd : 文件描述符
* speed : 串口速度
* flow_ctrl 数据流控制
* databits 数据位 取值为 7 或者8
* stopbits 停止位 取值为 1 或者2
* parity 效验类型 取值为N,E,O,,S
*
* 出口参数: 正确返回为1,错误返回为0
*******************************************************************/
int uart_init(int fd, int speed,int flow_ctrl,int databits,int stopbits,int parity)
{
int err;
//设置串口数据帧格式
if (uart_set(fd,115200,0,8,'N',1) == FALSE)
{
return FALSE;
}
else
{
return TRUE;
}
}
/*******************************************************************
* 名称: uart_recv
* 功能: 接收串口数据
* 入口参数: fd :文件描述符
* rcv_buf :接收串口中数据存入rcv_buf缓冲区中
* data_len :一帧数据的长度
* 出口参数: 正确返回为1,错误返回为0
*******************************************************************/
int uart_recv(int fd, char *rcv_buf,int data_len)
{
int len,fs_sel;
fd_set fs_read;
/*fd_set是一组文件描述字(fd)的集合,
* 它用一位来表示一个fd,定义在头文件<sys/select.h>中定义常量FD_SETSIZE,一般可表示1024个ID
*/
struct timeval time;
FD_ZERO(&fs_read); /*初始化读取的集合*/
FD_SET(fd,&fs_read); /*用于在文件描述符集合中增加一个新的文件描述符*/
time.tv_sec = 1; /*等待1秒,超时则会退出*/
time.tv_usec = 0;
//使用select实现串口的多路通信
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);
printf("I am right!(version1.2) len = %d fs_sel = %d\n",len,fs_sel);
return len;
}
else
{
printf("Sorry,I am wrong!");
return FALSE;
}
}
/********************************************************************
* 名称: uart_send
* 功能: 发送数据
* 入口参数: fd :文件描述符
* send_buf :存放串口发送数据
* data_len :一帧数据的个数
* 出口参数: 正确返回为1,错误返回为0
*******************************************************************/
int uart_send(int fd, char *send_buf,int data_len)
{
int len = 0;
len = write(fd,send_buf,data_len);
if (len == data_len )
{
printf("send data is %s\n",send_buf);
return len;
}
else
{
tcflush(fd,TCOFLUSH);
return FALSE;
}
}
主程序如下:
#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 <string.h>
#include <assert.h>
#include "uart.h"
/*
*主程序,循环读取数据
*参数,./usar <参数数量> <路径> <参数cmd>
*cmd <0> 发送数据
* <1> 其他则循环读取数据
*/
int main(int argc, char **argv)
{
int fd; //文件描述符
int err; //返回调用函数的状态
int len;
int i;
char rcv_buf[100];
char send_buf[20]="123456789";
if(argc != 3)
{
printf("Usage: %s /dev/ttySn 0(send data)/1 (receive data) \n",argv[0]);
return FALSE;
}
fd = uart_open(fd,argv[1]); //打开串口,返回文件描述符,需要提供相应的路径
do
{
err = uart_init(fd,115200,0,8,1,'N');
printf("Set Port Exactly!\n");
sleep(1);
}while(FALSE == err || FALSE == fd);
if(0 == strcmp(argv[2],"0"))
{
for(i = 0;i < 10;i++)
{
len = uart_send(fd,send_buf,7);
if(len > 0)
printf(" %d time send %d data successful\n",i,len);
else
printf("send data failed!\n");
sleep(2);
}
uart_close(fd);
}
else
{
while (1) //循环读取数据
{
len = uart_recv(fd, rcv_buf,99);
if(len > 0)
{
rcv_buf[len] = '\0';
printf("receive data is %s\n",rcv_buf);
printf("len = %d\n",len);
}
else
{
printf("cannot receive data\n");
}
sleep(2);
}
uart_close(fd);
}
}
发送的数据到电脑,都不正确,但是数据是正确的,比如发送7个a接收到的为E1 E1 B8 B8 5C 5C FE,非常奇怪的现象,难道新唐的单片机有问题吗?
|
|