一、前言
本章介绍下OKG2L的uart引脚、测试方法以及如何处理迪文串口的uart信息。
二、硬件
2.1 电路图
OKG2L支持三个uart口,其中
GPIO33、35分别为rx,tx
在底板的P23,从下往上数左侧第9个为uart的rx(接收端),可以查看uart图标找到对应位置。
35是开发板的TX,33是开发板的RX。
使用电脑的串口工具时,连接usb ttl小板,开发板TX接小板RX。
2.2 连接图
连接迪文串口屏,开发板tx连接串口屏rx
连接如下图
三、代码
3.1 fltest_uarttest——官方实现uart基础测试
串口代码路径:drivers/tty/serial/sh-sci.c
开发板中路径:/dev/ttySX
外接的uart时ttySC1
官方提供的cmd:fltest_uarttest
fltest_uarttest工具代码路径:OKG2L-linux-sdk10\appsrc\forlinx-cmd\uarttest
我的代码也是基于这个增加了串口件通信。
PS:注意,这里是一位一位获取数据的,经我测试,一次读取最多8位,所以需要增加新的机制判断一组数据是否获取完毕。
详见如下问题一节。
3.2 实现迪文串口间通信
此代码为我基于官方实现添加了迪文串口屏的事件判定,开源,禁止商用,谢谢。
uart_example.c
#include "dwin.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>
#include <sys/time.h>
#include <string.h>
#include <getopt.h>
#include "stdbool.h"
#define uint8_t u_int8_t
#define bool _Bool
extern void u8_to_char(uint8_t * , char ** );
extern int judge_dwin_cmd(uint8_t ** );
extern int get_len(uint8_t *cmd_u8);
extern dwin_event_flag uart_judge_dwin_event(i_dwin_cmd * cmd);
extern i_dwin_cmd temp_cmd_recv;
extern dwin_event_key event_key_list[EVENT_KEY_NUM_MAX];
extern dwin_event_key_spec event_key_spec[EVENT_KEY_SPEC_NUM_MAX];
extern c_dwin_cmd cmd_recv_char;
extern c_dwin_cmd cmd_send_char;
extern dwin_event_flag c_judge_dwin_event(c_dwin_cmd * cmd);
extern void c_dwin_cmd_analysis(char * in,c_dwin_cmd *cmd);
extern void c_print_cmd(c_dwin_cmd *cmd);
#define UART_ID 0
#define UART_RECV_LEN 1024
#define BUF_RX_MAX 512
#define LEN_CHAR_TEMP 17
c_dwin_cmd cmd_char;
int search_str_end(uint8_t *str_z, int count)
{
int temp_zero = 1;
int temp_count = count -1;
printf("init count = %d, temp_count = %d\n",count,temp_count);
uint8_t *str_temp1 = str_z;
while(1)
{
printf("str = [%02X], temp_zero = [%d], temp_count = [%d]\n",*str_temp1,temp_zero,temp_count);
if(*str_temp1 != 0x00)
{
printf("value = %02X, %ld\n",*str_temp1,str_temp1-str_z);
temp_count += temp_zero;
str_temp1++;
temp_zero = 1;
}
else
{
temp_zero++;
printf("value = %02X, %ld\n",*str_temp1,str_temp1-str_z);
}
if(temp_zero > 10)
break;
}
printf("init count = %d, temp_count = %d\n",count,temp_count);
return temp_count;
}
int my_strlen(uint8_t *str)
{
printf("enter my_strlen");
uint8_t *str_temp = str;
int count = 0;
while (*str_temp != '\0')
{
printf("value = %02X, %ld\n",*str_temp,str_temp-str);
count++;
str_temp++;
}
count = search_str_end(str_temp-1,count);
return count;
}
int judge_char(uint8_t * str)
{
if (str != NULL){
printf("enter judge_char");
if (my_strlen(str) != 0) {
return 1;
}
else
return 0;
}
else
return -1;
}
void func_uart_write(uint8_t * str, int fd)
{
printf("enter func_uart_write");
unsigned int ret;
ret = write(fd, str, *(str+2));
if (ret <0)
{
printf("%s, %d: LzUartInit(%d) failed!\n", __FILE__, __LINE__, ret);
return;
}
}
void uint8_2_char(uint8_t * in,char * out, int cp_len)
{
printf("raw uint8_t data[");
int cmd_len=*(in+2)+3;
char tmp[3];
memset(tmp,0x00,3);
for(int i =0;i< cp_len;i++)
{
printf("%02X",*(in+i));
sprintf(tmp,"%02X",*(in+i));
strcat(out,tmp);
memset(tmp,0x00,3);
}
printf("]\n");
}
void main(void)
{
int fd;
int nread;
char buf_rx[BUF_RX_MAX+1];
int n=0,i=0;
char dev[] = "/dev/ttySC1";
struct termios oldtio,newtio;
speed_t speed = B115200;
int next_option,havearg = 0,flow = 0;
fd = open(dev, O_RDWR | O_NONBLOCK| O_NOCTTY | O_NDELAY);
if (fd < 0) {
printf("Can't Open Serial Port!\n");
exit(0);
}
printf("Welcome to uart buf_tx\n");
tcgetattr(fd,&oldtio);
bzero(&newtio,sizeof(newtio));
newtio.c_cflag = speed|CS8|CLOCAL|CREAD;
newtio.c_cflag &= ~CSTOPB;
newtio.c_cflag &= ~PARENB;
newtio.c_iflag = IGNPAR;
newtio.c_oflag = 0;
tcflush(fd,TCIFLUSH);
tcsetattr(fd,TCSANOW,&newtio);
tcgetattr(fd,&oldtio);
memset(buf_rx,0,BUF_RX_MAX+1);
char buf_tx[100]="forlinx_uart_test.1234567890...";
printf("Send buf_tx data:\n[%s] [%ld]\n",buf_tx,strlen(buf_tx));
write(fd, buf_tx, strlen(buf_tx));
fd_set rd;
int flag_rx=0;
bool flag_rx1= false;
bool flag_rx2 = false;
bool flag_print=true;
int cmd_len=0;
uint8_t str_send[UART_RECV_LEN] = "HelloWorld!\n";
char str_send_char[513] = "";
uint8_t recv_int8[UART_RECV_LEN];
char recv_char[UART_RECV_LEN];
uint8_t recv_int8_t[9];
char recv_char_t[LEN_CHAR_TEMP];
char *recv_char_p=NULL;
bool status_uart_send = false;
init_dwin_status();
uint8_t xxx[]={0X5A,0XA5,0X05,0X82,0X10,0X00,0X00,0X01};
char *yyy=(char *)malloc(get_len(recv_int8));
u8_to_char(xxx,&yyy);
printf("yyy = %s\n",yyy);
printf("enter while\n");
while (1)
{
memset(recv_int8_t,0x00,UART_RECV_LEN);
int nread = read(fd, recv_int8_t, UART_RECV_LEN);
if (nread > 0)
{
if(*recv_int8_t==0x5a && *(recv_int8_t+1)==0xa5)
{
cmd_len=*(recv_int8_t+2)+3;
cmd_len=2*cmd_len ;
printf("\ncmd len = %d\n",cmd_len);
}
memset(recv_char_t,0x00,LEN_CHAR_TEMP);
uint8_2_char(recv_int8_t,recv_char_t, nread);
strcat(recv_char,recv_char_t);
flag_rx1=true;
flag_rx2=true;
}
else if(nread < 0 )
{
printf("%s, %d: LzUartInit(%d) failed!\n", __FILE__, __LINE__, nread);
return;
}
if(nread == 0)
{
if(flag_rx1==true&&flag_rx2==true)
{
flag_rx2=false;
}
else if(flag_rx1==true&&flag_rx2==false)
{
flag_rx1=false;
if(strlen(recv_int8)>0)
{
if(strlen(recv_char)==cmd_len)
{
printf(">>>recv_cmd_char = [%s]\n",recv_char);
c_dwin_cmd_analysis(recv_char,&cmd_recv_char);
memset(recv_char,0x00,UART_RECV_LEN);
tcflush(fd, TCIOFLUSH);
}
}
}
}
}
close(fd);
return;
}
dwin.h
#include "stddef.h"
#include "string.h"
#include "stdio.h"
#include "stdlib.h"
#include "stdbool.h"
#include "stdint.h"
#define TRUE 1
#define FALSE 0
#define uint8_t u_int8_t
#define bool _Bool
typedef enum{
EVENT_FLAG_OK = 0X0,
EVENT_FLAG_AUDIO_RECORD = 0x3,
EVENT_FLAG_AUDIO_PLAY = 0x4,
EVENT_FLAG_CAM_SCAN = 0x5,
EVENT_FLAG_NFC_SCAN = 0x6,
EVENT_FLAG_BOOK_SEARCH = 0x10,
EVENT_FLAG_BOOK_INPUT = 0x11,
EVENT_FLAG_UNKOWN = -1,
}dwin_event_flag;
typedef enum{
EVENT_FLAG_STATUS_ING = TRUE,
EVENT_FLAG_STATUS_STOP = FALSE,
EVENT_FLAG_STATUS_ERROR = -1,
}dwin_event_flag_status;
typedef enum{
EVENT_TYPE_DWIN_SEND = 0x0,
EVENT_FLAG_DWIN_RECV = 0x1,
}dwin_event_type;
#define DWIN_CMD_LEN_U8_MAX 259
typedef struct
{
uint8_t head[2];
uint8_t len;
uint8_t wr;
uint8_t addr[2];
uint8_t * value;
uint8_t * cmd_u8;
char * cmd_char;
}i_dwin_cmd;
void uart_recv_value_cut(uint8_t * recv_all);
dwin_event_flag uart_judge_dwin_event(i_dwin_cmd * cmd);
void print_dwin_cmd(i_dwin_cmd cmd);
char * dwin_cmd_uint8_t2char(i_dwin_cmd cmd);
char * uint8_t2char(uint8_t value);
char * uint8_t2char_list(uint8_t * p_dwin_u8_value,int len);
void change_dwin_status(dwin_event_flag event_flag);
#define EVENT_KEY_NUM_MAX 10
void func_open_record();
void func_close_record();
void func_open_cam();
void func_close_cam();
void func_open_nfc();
void func_close_nfc();
#define EVENT_NAME_MAX 11
#define EVENT_FLAG_NAME_MAX 30
#define EVENT_KEY_VALUE_MAX 11
typedef struct
{
dwin_event_flag flag;
char event_name[EVENT_NAME_MAX];
dwin_event_flag_status status;
char key[EVENT_KEY_VALUE_MAX];
char flag_name[EVENT_FLAG_NAME_MAX];
void (*open)();
void (*close)();
}dwin_event_key;
dwin_event_key event_key_list[EVENT_KEY_NUM_MAX];
typedef struct
{
char key[EVENT_KEY_VALUE_MAX];
char event_name[EVENT_FLAG_NAME_MAX];
void (*func)();
}dwin_event_key_spec;
void func_search();
void func_spec_end();
void searc_spec_event();
#define EVENT_KEY_SPEC_VALUE "over"
#define EVENT_KEY_SPEC_NUM_MAX 20
dwin_event_key_spec event_key_spec[EVENT_KEY_SPEC_NUM_MAX];
void change_dwin_status_key(dwin_event_key *in_key);
void change_cmd_send_status(dwin_event_flag temp_event_flag);
void copy_u8_2_u8(uint8_t * u8_raw);
void u8_to_char(uint8_t * in_u8, char ** out);
uint8_t * u8_to_u8(uint8_t * in_u8);
void dwin_cmd_init_send();
void init_dwin_status();
void i_dwin_cmd_clear(i_dwin_cmd * cmd);
void uart_dwin_cmd_analysis(uint8_t *str);
void copy_u8_to_cmdu8(i_dwin_cmd *cmd, uint8_t * u8);
#define DWIN_CMD_CHAR_ADDR_VALUE 8
#define DWIN_CMD_CHAR_VALUE_VALUE 12
#define DWIN_CMD_CHAR_MAX 513
#define DWIN_CMD_U8_MAX 256
#define C_CMD_POINT_HEAD 0
#define C_CMD_POINT_LEN 4
#define C_CMD_POINT_WR 6
#define C_CMD_POINT_ADDR 8
#define C_CMD_POINT_VALUE 12
typedef struct
{
char head[5];
char len[3];
char wr[3];
char addr[5];
char * value;
char * cmd_char;
}c_dwin_cmd;
四、测试结果
这是检索事件
录音及停止事件
扫码及停止
nfc检索及停止
PS:电子发烧友的代码显示有异常,有兴趣的话去我的csdn查看,后续会更新出来。
https://blog.csdn.net/qq_38091632
六、编译
命令:$CC uart_example.c dwin.c -o dwin_test
五、问题
5.1 字符串地址传递
void u8_to_char(uint8_t * , char ** );
子函数内如果使用malloc分配空间,建议使用char **进行地址传递。
也可以在main函数中先分配,再传指针进子函数。
5.2 uart数据
串口传输可以选择hex还是字符串,我们在使用串口工具测试时选择hex,模拟实际迪文屏数据传输。
此外注意传入的数据为uint_8,需要转换为字符串进行分析。
原数据:0x5AA5
字符串:"5AA5"
传出时再进行字符串转为uint_8
5.3 一次接收8位
使用read函数对ttySC1进行读取,一次只能读8位。
由于迪文屏的串口数据结构,其中的第三个字节传输的是后续数据的长度。
比如0x5AA5 06 82 1000 01 1234
其中的06就是后续的82 1000 01 1234长度,所以先计算出一组数据长度为06+3,3是前面的5AA5加上len。
代码中先判断head为5AA5,然后存入len,当接收到的字符串长度为len*2,一组接收完毕。
乘以2是因为uint_8转换为两位char。
六、小结
串口通信较为简单,实现了基础的读写功能后再结合串口屏的传输协议进行数据处理。
此功能应该适用于其他linux开发板,后续可以在其他平台上试试。
目前上述代码只是实现了基本的事件判断架构,后续各种判断条件可以自行添加,只需要定义匹配的字符串以及执行的函数即可。
最后,感谢飞凌提供的试用机会。