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
#include
#include
#include
#include
#include
#include
#include
#include
#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;
}