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