STM32串口通信代码、ASCII码、XU4串口通信,printf只会转换为无符号类型,linux下的串口通信程序

1、其里面的的通信协议是是自己定的,这里 是检测到数据的结尾是以0x0d、0x0a结尾,则表示接受的数据完成了,这个数据是我想要的,这样子就不会出现一些错乱的数据信息。其中的0x8000、0x4000只是一个标志位来的。

原子哥,我是新手,最近看到串口通信那一块,那个串口中断函数那里

void USART1_IRQHandler(void)                	//串口1中断服务程序
{
u8 Res;
#ifdef OS_TICKS_PER_SEC	//如果时钟节拍数定义了,说明要使用ucosII了.
OSIntEnter();    
#endif
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //接收中断(接收到的数据必须是0x0d 0x0a结尾)
{
Res =USART_ReceiveData(USART1);//(USART1->DR);	//读取接收到的数据

if((USART_RX_STA&0x8000)==0)//接收未完成
{
if(USART_RX_STA&0x4000)//接收

a、这里的数据加的0d、0a分别是回车、换行的十六进制,当我们编写程序的时候需要在数据的结尾加上这两个十六进制,否则接受端会以接受不到这两个数据,而丢弃所接受的数据。

b、其中ASCII跟十六进制的关系 ,其中ASCII码就是字符

ASCII与16进制转换

ASCII

16进制

ASCII

16进制

ASCII

16进制

ASCII

16进制

NUL

00H

DLE

10H

SP

20H

0

30H

SOH

01H

DC1

11H

!

21H

1

31H

STX

02H

DC2

12H

"

22H

2

32H

ETX

03H

DC3

13H

#

23H

3

33H

EOT

04H

DC4

14H

$

24H

4

34H

ENQ

05H

NAK

15H

%

25H

5

35H

ACK

06H

SYN

16H

&

26H

6

36H

BEL

07H

ETB

17H

 '

27H

7

37H

BS

08H

CAN

18H

(

28H

8

38H

HT

09H

EM

19H

)

29H

9

39H

LF

0AH

SUB

1AH

*

2AH

:

3AH

VT

0BH

ESC

1BH

 +

2BH

;

3BH

FF

0CH

FS

1CH

,

2CH

3CH

CR

0DH

GS

1DH

 _

2DH

 =

3DH

SO

0EH

RS

1EH

.

2EH

3EH

SI

0FH

US

1FH

/

2FH

3FH

ASCII

16进制

ASCII

16进制

ASCII

16进制

ASCII

16进制

40H

P

50H

60H

p

70H

A

41H

Q

51H

a

61H

q

71H

B

42H

R

52H

b

62H

r

72H

C

43H

S

53H

c

63H

s

73H

D

44H

T

54H

d

64H

t

74H

E

45H

U

55H

e

65H

u

75H

F

46H

V

56H

f

66H

v

76H

G

47H

W

57H

g

67H

w

77H

H

48H

X

58H

h

68H

x

78H

I

49H

Y

59H

i

69H

y

79H

J

4AH

Z

5AH

j

6AH

z

7AH

K

4BH

5BH

k

6BH

7BH

L

4CH

5CH

l

6CH

7CH

M

4DH

5DH

m

6DH

7DH

N

4EH

5EH

n

6EH

7EH

O

4FH

5FH

o

6FH

DEL

7FH

    关于这张表,主要是键盘上的键值字符在计算机中的二进制存储,为了方便,转化成的16进制表示。
所以,45的ASCII表示就是4的ASCII表示和5的ASCII表示联结起来的。
每个ASCII字符转化成16进制是两位的16进制数,即一个字节,同样,把16进制数转化成ASCII时是两位一起转化成一个ASCII字符,然后把他们联结起来。

   注意:计算机串口通信都是以二进制的0、1来进行通信的,我们所说的发送字符即也是ASCII码、数值。其发送是转换成二进制,而二进制一般是从十六进制转换来的,所以,这两都需转换为十六进制,然后变为二进制进行传输,而在接收端,则是把这些接收到的二进制进行解析,这需要根据协议来进行解析的,例如

传送端发送ASCII码为:a字符

计算机传输时先转为:61H   然后变为:0110 0001  最后进行传输

接收端定义一个char型字符jj,然后jj读取,然后其在程序中就可以使用了,假如作为标志位;则

if(jj=='a')..

或者if(jj==97)..

其实jj里面存储着的是8位的二进制,就看自己怎么转换了,其中的int里存储的是32位二进制。下面就是说明这个的例如printf:

int Data=97;
nTen=write(nFd,&Data,4);
nRet=read(nFd,&Data,4);
printf("Recv Data:%c\n",Data);
输出的结果是:Recv Data:a
如果为printf("Recv Data:%d\n",Data);
输出的结果是:Recv Data:97
    还有假如我们传输的字符在这ASCII码表里没有的话,需要定义一个标准,例如汉字表,这是国家定义的标准,功能跟ASCII码表一样,如果没有这些的话,我们传输的字符显示出来是会乱码的。

   其中printf其只会转为无符号类型。例如

int Data=-2;

printf("Recv Data:%d\n",Data);

输出结果是:254

负数的反码减去2。


 2、Odroid XU4与3.3v的ttl接口通信问题

a、odroid XU4的TTL口的RX、TX与3.3v芯片的TTL口RX、TX进行通信,其中XU4的RX能正确接受到3.3V芯片的TX传来的数据,但是XU4的TX无法与

芯片的RX通信,其识别不了。

b、odroid XU4的TTL口的RX、TX与PL2303串口模块的RX、TX进行通信,其能够完成双向通信,但是,有时PL2303接受到的数据会出现乱码,

解决方法:在传输的数据后面加上'\r'、'\n'这样子PL2303接受的数据就变得很正常了。

其如下:


      putty显示不了中文,其是因为它这里没有中文字库,所以这里由于在ASCII码表了找不到转换,则出现乱码。一般当通讯的时候使用了中文,则其是根据中文字库转换为很多的二进制,然后在另一端再根据中文字库来解析出中文了,其是不能依靠ASCII码表来转换的。

3、linux下的串口通信程序代码:

#ifndef _RECV_H
#define _RECV_H
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#define BAUDRATE B115200 ///Baud rate : 115200
#define DEVICE "/dev/ttyAMA0"
#define SIZE 1024
#endif
#include "Recv.h"
int nFd = 0;
struct termios stNew;
struct termios stOld;

int SerialInit()
{
	nFd = open(DEVICE, O_RDWR | O_NOCTTY | O_NDELAY);
	if (-1 == nFd)
	{
		perror("Open Serial Port Error!\n");
		return -1;
	}
	/*这里是设置通信模式,其有阻塞、非阻塞。
	当第三个设为0则是阻塞,FNDELAY为非阻塞*/
	if ((fcntl(nFd, F_SETFL, 0)) < 0)  
	{
		perror("Fcntl F_SETFL Error!\n");
		return -1;
	}
	if (tcgetattr(nFd, &stOld) != 0)
	{
		perror("tcgetattr error!\n");
		return -1;
	}
	stNew = stOld;
	cfmakeraw(&stNew);//将终端设置为原始模式,该模式下所有的输入数据以字节为单位被处理
	//set speed
	cfsetispeed(&stNew, BAUDRATE);//115200
	cfsetospeed(&stNew, BAUDRATE);
	//set databits
	stNew.c_cflag |= (CLOCAL | CREAD);
	stNew.c_cflag &= ~CSIZE;
	stNew.c_cflag |= CS8;
	//set parity
	stNew.c_cflag &= ~PARENB;
	stNew.c_iflag &= ~INPCK;
	//set stopbits
	stNew.c_cflag &= ~CSTOPB;
	stNew.c_cc[VTIME] = 0;    //指定所要读取字符的最小数量
	stNew.c_cc[VMIN] = 1; //指定读取第一个字符的等待时间,时间的单位为n*100ms
	//如果设置VTIME=0,则无字符输入时read()操作无限期的阻塞
	tcflush(nFd, TCIFLUSH);  //清空终端未完成的输入请求及数据。这个一般需要不断的放到死循环里
	if (tcsetattr(nFd, TCSANOW, &stNew) != 0)
	{
		perror("tcsetattr Error!\n");
		return -1;
	}
	return nFd;
}
int main(int argc, char **argv)
{
	int nRet = 0;
	char buf[SIZE];
	if (SerialInit() == -1)
	{
		perror("SerialInit Error!\n");
		return -1;
	}
	bzero(buf, SIZE);
	while (1)
	{

		nRet = read(nFd, buf, SIZE);
        /*这里要不断清楚接受缓存里的数据,因为其里面可能存有很多先前的数据,
		这就导致,即使没有发生数据,这里也会读到数据。*/
		tcflush(nFd, TCIFLUSH); 
		if (-1 == nRet)
		{
			perror("Read Data Error!\n");
			break;
		}
		if (0 < nRet)
		{
			buf[nRet] = 0;
			printf("Recv Data: %s\n", buf); /*%x是十六进制,这里是以ascII码显示*/
		}
	}
	close(nFd);
	return 0;
}
  阻塞模式:就是read()未接受到数据则不返回,非阻塞模式:就是read()即使为接受到数据也返回。记住设置这两个模式 不是通过设置VTIME、VMIN

还有读取数据后提起想要的数据时,要注意的相与是‘&’而不是‘&&’,例如:

                                        zhentou0=Zdepth&0xff;
                                        zhentou1=Zdepth>>8&0xff;
                                        hht=Zdepth>>16&0xffff;
                                        if(zhentou0==0xeb&&zhentou1==0x90)
                                        {
				        Zdepth=hht; 
                                        }else{
                                        Zdepth=0;
                                        }







已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 代码科技 设计师:Amelia_0503 返回首页