您的位置:首页 > 运维架构 > Linux

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

2016-11-16 15:48 1016 查看
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;
}


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: