{背景}
1. 使用模拟方式与PSAM卡进行通信,对时序的要求非常严格,在自己的代码中一定要做好相关延时尤其是每个etu的时间
要测量准确。
2. 使用串口方式与PSAM卡直连,是硬件级的通信,写起来相对容易一些。
{遇到的问题}
1. 串口应用收不到PSAM卡的复位信息
2. 串口的TX 在RX 有数据时发出干扰数据
{解决方案}
1、问题一的解决方案
设置串口为8个数据位,2位停止位,偶校验位。
set_Parity(uart_fd, 8, 2, 'E')
设置串口参数为原始模式,这样才能正确收到PSAM复位信息
options.c_lflag &= ~(ICANON); // config as original mode.
2. 问题二的解决方案
设置串口参数关闭回显,这样TX 就不会再出现干扰信息。
options.c_lflag &= ~(ECHO | ECHONL | ISIG); // disable echo
{参考代码}
#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>#define TRUE 1 #define FALSE -1int speed_arr[] = { B230400, B115200, B38400, B19200, B9600, B4800, B2400, B1200, B300, B38400, B19200, B9600, B4800, B2400, B1200, B300, }; int name_arr[] = { 230400, 115200, 38400, 19200, 9600, 4800, 2400, 1200, 300,38400, 19200, 9600, 4800, 2400, 1200, 300, };void set_speed(int fd, int speed) {int i;int status;struct termios Opt;tcgetattr(fd, &Opt);for (i = 0; i < sizeof(speed_arr) / sizeof(int); i++) {if (speed == name_arr[i]) {tcflush(fd, TCIOFLUSH);// set baudratecfsetispeed(&Opt, speed_arr[i]);cfsetospeed(&Opt, speed_arr[i]);status = tcsetattr(fd, TCSANOW, &Opt);if (status != 0) {perror("tcsetattr fd1");}return;}tcflush(fd, TCIOFLUSH);} }/***@brief 设置串口数据位,停止位和校验位*@param fd 类型 int 打开的串口文件句柄*@param databits 类型 int 数据位 取值为7或者8*@param stopbits 类型 int 停止位 取值为1或者2*@param parity 类型 int 奇偶校验位 取值 N, E, O, S*/ int set_Parity(int fd, int databits, int stopbits, int parity) {struct termios options;if (tcgetattr(fd, &options) != 0) {perror("SetupSerial 1");return (FALSE);}options.c_cflag &= ~CSIZE;switch (databits) {case 7:options.c_cflag |= CS7;break;case 8:options.c_cflag |= CS8;break;default:fprintf(stderr, "Unsupported data size\n");return FALSE;}switch (parity) {case 'n':case 'N':options.c_cflag &= ~PARENB; /* Clear parity enable */options.c_iflag &= ~INPCK; /* Enable parity checking */options.c_iflag &= ~(ICRNL | IGNCR);options.c_lflag &= ~(ICANON);break;case 'o':case 'O':options.c_cflag |= (PARODD | PARENB); // 设置为奇校验位options.c_iflag |= INPCK; /* Disnable parity checking */break;case 'e':case 'E':options.c_cflag |= PARENB; // Enable parity checkoptions.c_cflag &= ~PARODD; // config as even parity checkoptions.c_iflag |= INPCK; // enable input parity checkoptions.c_oflag &= ~OPOST; // output for raw modeoptions.c_lflag &= ~(ICANON); // config as original mode. MUST be configured.options.c_lflag &= ~(ECHO | ECHONL | ISIG); // disable echo break;case 'S':case 's': /*as no parity*/options.c_cflag &= ~PARENB;options.c_cflag &= ~CSTOPB;break;default:fprintf(stderr, "Unsupported parity\n");return FALSE;}// set stop bitsswitch (stopbits) {case 1:options.c_cflag &= ~CSTOPB;break;case 2:options.c_cflag |= CSTOPB;break;default:fprintf(stderr, "Unsupported stop bits\n");return FALSE;}/* Set input parity option */if (parity != 'n') {options.c_iflag |= INPCK;}//options.c_cc[VTIME] = 150; // 15 secondsoptions.c_cc[VTIME] = 50; // 5 secondsoptions.c_cc[VMIN] = 0;options.c_iflag &= ~(ICRNL | IXON);tcflush(fd, TCIFLUSH); /* Update the options and do it NOW */if (tcsetattr(fd, TCSANOW, &options) != 0) {perror("SetupSerial 3");return FALSE;}return TRUE; }int OpenDev(char *Dev) {int fd = open(Dev, O_RDWR);if (-1 == fd) {perror("Can't Open Serial Port");return -1;} else {return fd;} }int CloseDev(int Dev) {int fd = close(Dev);if (-1 == fd) {perror("Can't close Serial Port");return -1;} else {return fd;} }// // input: e.g. "/dev/ttymxc3" // output: valid uart_fd or -1 for open error, -2 for set parity error // int uart_cfg(char *which_uart, int speed) {int uart_fd;if (which_uart == NULL) {perror("input parameter invalid.");}uart_fd = OpenDev(which_uart);if (uart_fd > 0) {set_speed(uart_fd, speed);printf("open success, 9600\n");} else {printf("Open Failure!\n");return -1;}if (set_Parity(uart_fd, 8, 2, 'E') == FALSE) {printf("Set Parity Error\n");return -2;} else {printf("parity set as 8,2,E\n");}return uart_fd; }void psam_send_cmd(int fd, unsigned char *cmd_buf, unsigned int cmd_len) {if (cmd_buf == NULL || cmd_len == 0 || fd < 0) {perror("Invalid parameter.");}if (write(fd, cmd_buf, cmd_len) != cmd_len) {printf("send psam cmd failed!\n");} }void psam_get_cmd_response(int fd, int res_len) {int i = 0;int read_byte = 0;unsigned char res = 0;for (i = 0; i < res_len; i++) {read_byte = read(fd, &res, 1);if (read_byte > 0) {printf("%2x ", res);} else {break;}}printf("\n"); }int main(int argc, char **argv) {int nread = 0;int uart_fd = 0;// open uart3int current_speed = 9600;char *dev = "/dev/ttymxc3";uart_fd = uart_cfg(dev, current_speed);if (uart_fd < 0) {perror("uart cfg error.");exit(1);}printf("\nWelcome to PSAM CARD tests\n\n");unsigned char cmd_pps[4] = { 0xFF, 0x10, 0x95, 0x7A };unsigned char cmd_get_rand[5] = { 0x00, 0x84, 0x00, 0x00, 0x08 };unsigned char cmd_select_3F00[7] = { 0x00, 0xA4, 0x00, 0x00, 0x02, 0x3F, 0x00 };unsigned char cmd_select_0015[7] = { 0x00, 0xA4, 0x00, 0x00, 0x02, 0x00, 0x15 };unsigned char cmd_get_num[5] = { 0x00, 0xB0, 0x96, 0x00, 0x06 };unsigned char res = 0x00;int choice = 0;int speed_choice = 0;while (1) {if (choice != '\n') {printf("\n");printf("Input you select.\n");printf("\t=== Psam Test ===\n");printf("\t a. pps to 115200\n");printf("\t b. get_rand_number\n");printf("\t c. get_psam_number\n");printf("\t d. Test Rest ATR\n");printf("\t f. set baudrate\n");}choice = getchar();switch (choice) {case 'a': // pps cmdprintf("pps selected.\n");psam_send_cmd(uart_fd, cmd_pps, 4);psam_get_cmd_response(uart_fd, 19);set_speed(uart_fd, 115200);printf("*** Current speed is 115200\n");break;case 'b':printf("get_rand_number selected.\n");psam_send_cmd(uart_fd, cmd_get_rand, 5);psam_get_cmd_response(uart_fd, 11);break;case 'c': // attention: if cmd length larger than 5 bytes, send 5 bytes first, __FIXME__printf("get_psam_number selected.\n"); // // select 3F00printf("1) select 3F00\n");psam_send_cmd(uart_fd, cmd_select_3F00, 7);psam_get_cmd_response(uart_fd, 15);printf("\n");// select 0015printf("2) select 0015\n");psam_send_cmd(uart_fd, cmd_select_0015, 7);psam_get_cmd_response(uart_fd, 20);printf("\n");// read psam numberprintf("3) get psam number\n");psam_send_cmd(uart_fd, cmd_get_num, 5);psam_get_cmd_response(uart_fd, 20);printf("\n");break;case 'd':psam_get_cmd_response(uart_fd, 15);break;case 'f': {if (choice != '\n') {printf("\t current speed is %d\n", current_speed);printf("\n");printf("\t=== baudrate set ===\n");printf("\t 1. 115200\n");printf("\t 2. 38400\n");printf("\t 3. 9600\n");printf("\t 9. Exit\n");printf("\n");}scanf("%d", &speed_choice);switch (speed_choice) {case 1: // 115200current_speed = 115200;set_speed(uart_fd, 115200);printf("*** Current speed is 115200\n");break;case 2: // 38400current_speed = 38400;set_speed(uart_fd, 38400);printf("*** Current speed is 38400\n");break;case 3: // 9600current_speed = 9600;set_speed(uart_fd, 9600);printf("*** Current speed is 9600\n");break;case 9:break;}}break;default:break;}} }