Linux和单片机通信

lyz998 2017-06-02 02:46:31
这是linux代码,
while(1){
printf("请输入控制命令(1-来打招呼,2-接受数据,3-走打招呼):");
scanf("%d", &num);
if (num == 1){
serSend(fd, str1, 1);
memset(str, 0, sizeof(str));
/*while (serRev(fd, &ch, 1) > 0);
printf("%c",ch);
serSend(fd, str1, 1);*/
lseek(fd,0,SEEK_SET);
while ((len = serRev(fd, str, 17)) == 0);
printf("\nRecvLen %d",len);
str[len]='\0';
printf("\nRecv:%s\n", str);
}
else if (num == 2){
serSend(fd, str2, 1);
memset(str, 0, sizeof(str));
serRev(fd, str, 4);
printf("\nRecv:%s\n", str);
}
else if (num == 3){
serSend(fd, str3, 1);
memset(str, 0, sizeof(str));
lseek(fd,0,SEEK_SET);
while (serRev(fd, str, 8) == 0);
printf("\nRecv:%s\n", str);
}
memset(str, 0, sizeof(str));
}




问题说明:目的是1命令:linux发A,单片机回@ linux在发@ 单片机回复字符串Welcome to water
3命令:linux发C,单片机回字符串
实际问题是:linux发A,单片机回@ linux发A,收到W 再发A (忽略收@ )收到elcome to wate 再发A 才能接受完整
当linux 在发C时 read先收到Welcome to water 第二次才能收到GoodBye 如果开始就发C,情况类似
我怀疑可能是write同时发了两次,read为什么第一次只读一个字节
单片机代码

void InitUART(){

SCON = 0x50;
TMOD |= 0x20;
TH1 = 0xF3;
TR1 = 1;
}
void WaterInit(){

TMOD |= 0x05;
TH0=0;
TL0=0;
TR0=1;
}
void main (void)
{
uchar str[6], A = 0;
InitUART();
WaterInit();
EA = 1;

while (TI == 0)
{
while(RI == 0){
num = 256 * TH0 + TL0;
ISR();
Display(Qian,Bai,Shi,Ge);
}
if (SBUF == 'B'){
sprintf(str,"%u",num);
SendStr(str);
TR0 = 1;
}
else if(SBUF == 'A'){
if (A == 0){
SendByte('@');
TR0 = 1;
A = 1;
}
else if (A == 1){
SendStr("Welcome to water!");
TR0 = 1;
A = 0;
}
}
else if(SBUF == 'C'){
SendStr("GoodBye!");
A = 0;
TR0 = 1;
}
RI = 0;
}
}

/*------------------------------------------------
发送一个字节
------------------------------------------------*/
void SendByte(unsigned char dat)
{
SBUF = dat;
while(!TI);
TI = 0;
}
/*------------------------------------------------
发送一个字符串
------------------------------------------------*/
void SendStr(unsigned char *s){
while(*s!='\0'){// \0 表示字符串结束标志,
//通过检测是否字符串末尾
SendByte(*s);
s++;
}
}


minicom串口显示没问题,isp显示也没有问题
...全文
823 8 打赏 收藏 转发到动态 举报
写回复
用AI写文章
8 条回复
切换为时间正序
请发表友善的回复…
发表回复
jklinux 2017-06-20
  • 打赏
  • 举报
回复
引用 7 楼 lyz998 的回复:
[quote=引用 6 楼 jklinux 的回复:] [quote=引用 5 楼 lyz998 的回复:] [quote=引用 3 楼 jklinux 的回复:] 简单点就专用一个子线程接收数据就可以了
printf("请输入控制命令(1-来打招呼,2-接受数据,3-走打招呼):");
		scanf("%d", &num);
		if (num == 1){
			serSend(fd, &str1, 1);
			process(fd);
		}	
		else if (num == 2){
			serSend(fd, &str2, 1);
			process(fd);	
		}
		else if (num == 3){
			serSend(fd, &str3, 1);
			process(fd);
		}
调用[/quote] 子线程只要创建一个就可以了,在main函数里调用一次pthread_create即可。 线程里应是死循环来接收串口数据的,不要随便退出.[/quote]
void* recv_func(void *args)
{
	unsigned char str[100];
	int fd = *(int*)args;
	int len = 0;

	while(1){
		memset(str, 0, sizeof(str));
		while ((len = serRev(fd, str, 30)) <= 0){}
		printf("\nRecvLen:%d",len);
		str[len]='\0';
		printf("\nRecv:%s\n", str);
	}
	/*pthread_exit(NULL);
    return;*/
}
我线程改成这样了,main只调用了一次, 但是收不到数据了,,判断是否接收到数据是这样判断吗?[/quote]


#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <pthread.h>


void *thread_func(void *arg)
{
	int fd = *(int *)arg;
	char data[100];
	int ret;

	while (1)
	{
		ret = read(0, data, sizeof(data));
		if (ret > 0)
		{
			data[ret-1] = '\r';
			write(fd, data, ret);	
		}
	}


	return NULL;
}

int main(int argc, char *argv[])
{
	int fd;

	fd = open(argv[1], O_RDWR|O_NOCTTY|O_NONBLOCK);
	if (fd < 0)
	{
		perror("open");
		return 1;
	}

	fcntl(fd, F_SETFL, 0);

	struct	termios opts;

	tcgetattr(fd, &opts);

	cfsetispeed(&opts, B115200);
	cfsetospeed(&opts, B115200);

	opts.c_cflag |= CREAD|CLOCAL;
	
	opts.c_cflag &= ~CSIZE;
	opts.c_cflag |= CS8;
	opts.c_cflag &= ~PARENB;
	opts.c_cflag &= ~CSTOPB;

	opts.c_cflag &= ~CRTSCTS;

	opts.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
	opts.c_oflag &= ~OPOST;	

	tcsetattr(fd,TCSANOW , &opts);
	/////////////
	pthread_t tid;

	pthread_create(&tid, NULL, thread_func, &fd); 
	

	int ret;
	char ch;
	while (1)
	{
		read(fd, &ch, 1);
	
		putchar(ch);
	}

	return 0;
}
你参考下
lyz998 2017-06-19
  • 打赏
  • 举报
回复
引用 6 楼 jklinux 的回复:
[quote=引用 5 楼 lyz998 的回复:] [quote=引用 3 楼 jklinux 的回复:] 简单点就专用一个子线程接收数据就可以了
printf("请输入控制命令(1-来打招呼,2-接受数据,3-走打招呼):");
		scanf("%d", &num);
		if (num == 1){
			serSend(fd, &str1, 1);
			process(fd);
		}	
		else if (num == 2){
			serSend(fd, &str2, 1);
			process(fd);	
		}
		else if (num == 3){
			serSend(fd, &str3, 1);
			process(fd);
		}
调用[/quote] 子线程只要创建一个就可以了,在main函数里调用一次pthread_create即可。 线程里应是死循环来接收串口数据的,不要随便退出.[/quote]
void* recv_func(void *args)
{
	unsigned char str[100];
	int fd = *(int*)args;
	int len = 0;

	while(1){
		memset(str, 0, sizeof(str));
		while ((len = serRev(fd, str, 30)) <= 0){}
		printf("\nRecvLen:%d",len);
		str[len]='\0';
		printf("\nRecv:%s\n", str);
	}
	/*pthread_exit(NULL);
    return;*/
}
我线程改成这样了,main只调用了一次, 但是收不到数据了,,判断是否接收到数据是这样判断吗?
jklinux 2017-06-19
  • 打赏
  • 举报
回复
引用 5 楼 lyz998 的回复:
[quote=引用 3 楼 jklinux 的回复:] 简单点就专用一个子线程接收数据就可以了
printf("请输入控制命令(1-来打招呼,2-接受数据,3-走打招呼):");
		scanf("%d", &num);
		if (num == 1){
			serSend(fd, &str1, 1);
			process(fd);
		}	
		else if (num == 2){
			serSend(fd, &str2, 1);
			process(fd);	
		}
		else if (num == 3){
			serSend(fd, &str3, 1);
			process(fd);
		}
调用[/quote] 子线程只要创建一个就可以了,在main函数里调用一次pthread_create即可。 线程里应是死循环来接收串口数据的,不要随便退出.
lyz998 2017-06-19
  • 打赏
  • 举报
回复
引用 3 楼 jklinux 的回复:
简单点就专用一个子线程接收数据就可以了
printf("请输入控制命令(1-来打招呼,2-接受数据,3-走打招呼):");
		scanf("%d", &num);
		if (num == 1){
			serSend(fd, &str1, 1);
			process(fd);
		}	
		else if (num == 2){
			serSend(fd, &str2, 1);
			process(fd);	
		}
		else if (num == 3){
			serSend(fd, &str3, 1);
			process(fd);
		}
调用
lyz998 2017-06-19
  • 打赏
  • 举报
回复
引用 3 楼 jklinux 的回复:
简单点就专用一个子线程接收数据就可以了

嗯嗯,,,我写了,,解决了一些问题但是又出现两个问题
一个是在第一次发送的时候,如下

第二个问题,,发送另一个命令时,会重复一遍

void* recv_func(void *args)
{
unsigned char str[100];
int fd = *(int*)args;
int len;

memset(str, 0, sizeof(str));
while ((len = serRev(fd, str, 30)) <= 0){}
printf("\nRecvLen:%d",len);
str[len]='\0';
printf("\nRecv:%s\n", str);
pthread_exit(NULL);
return;
}

void process(int fd)
{
pthread_t td;
int res;

res = pthread_create(&td, NULL, recv_func, (void*)&fd);
if(res != 0){
printf ("Create pthread error!\n");
exit (1);
}
pthread_join(td, NULL);
return;
}
jklinux 2017-06-14
  • 打赏
  • 举报
回复
简单点就专用一个子线程接收数据就可以了
lyz998 2017-06-13
  • 打赏
  • 举报
回复
引用 1 楼 jklinux 的回复:
对于linux端的代码我有点不明: 1). fd是uart设备打开得到的文件描述符吧? 如是, 则lseek(fd,0,SEEK_SET)是没有用的. 2). uart设备是全双工的,可同时收发. 楼主里的代码是发完了再来接收,这样有可能已丢失部分数据的。建议用个子线程专用于uart接收再试试吧
对,fd是是设备,这是接受函数,,,你的意思是,我在发的同时也在接收?该如何解决接受问题。。。 int serRev(int fd,char *buff,int len) { if (fd>0) { return(read(fd,buff,len)); }else { return(0); } }
jklinux 2017-06-04
  • 打赏
  • 举报
回复
对于linux端的代码我有点不明: 1). fd是uart设备打开得到的文件描述符吧? 如是, 则lseek(fd,0,SEEK_SET)是没有用的. 2). uart设备是全双工的,可同时收发. 楼主里的代码是发完了再来接收,这样有可能已丢失部分数据的。建议用个子线程专用于uart接收再试试吧

21,597

社区成员

发帖
与我相关
我的任务
社区描述
硬件/嵌入开发 驱动开发/核心开发
社区管理员
  • 驱动开发/核心开发社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧