├── .gitignore ├── Makefile ├── README.md ├── documents ├── ad.jpg └── stm32isp application note.pdf ├── include ├── stm32isp.h └── wiringSerial.h ├── main.c ├── stm32_test.bin ├── stm32isp.c └── wiringSerial.c /.gitignore: -------------------------------------------------------------------------------- 1 | stm32isp 2 | *.o 3 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | stm32isp: main.c wiringSerial.c stm32isp.c 2 | gcc main.c wiringSerial.c stm32isp.c -Iinclude -o stm32isp 3 | 4 | clean: 5 | rm stm32isp 6 | 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # 概述 3 | 4 | stm32串口ISP程序,基于c语言。 5 | 在ubuntu和mac下测试都ok,ubuntu下需要修改/dev/ttyUSB0权限,mac下不需要修改。 6 | 本程序在stm32f103c8t6上ok,根据官方文档,其他型号单片机下载协议相同,但没有测试过。 7 | 8 | 2019年04月10日:在mac下测试,用pl2303 ok,用ft232失败。 9 | 2020年12月03日:ft232失败原因应该是驱动问题导致延时过大,mac下老的ft232驱动收发大约会有几百ms延时,更新驱动后延时可控制在10ms以内。参考: 10 | 11 | 使用方法: 12 | **stm32isp /dev/ttyUSB0 stm32_test.bin** 13 | (mac下的usb串口节点是 /dev/tty.usbserial) 14 | 15 | 注: 16 | 17 | 1. 波特率固定为57600不允许修改。实际上测试了各种波特率,只有57600和38400可以稳定下载(程序写的还不太稳定吧),所以波特率固定为了57600。 18 | 2. **下载的是bin文件,不是hex文件**。bin文件是纯粹的编码,hex文件包含了地址信息。keil默认不生成bin文件,生成bin文件的方法可网上查找。 19 | 20 | # 下载协议 21 | 22 | stm32官方文档已提交到本工程 documents 目录下。 23 | 24 | ## 1、硬件 25 | 首先要让stm32进入bootloader启动: 26 | 27 | 引脚 | 电平 28 | :-: | :-: 29 | BOOT0 | 高电平 30 | BOOT1 | 低电平 31 | 32 | 这样启动后就会从system分区启动,开始接收串口数据。 33 | 34 | 连接串口1: 35 | 36 | 引脚 | 功能 37 | :-: | :-: 38 | PA9 | TXD,连接host RXD 39 | PA10 | RXD,连接host TXD 40 | 41 | ## 2、sync 42 | 以下数据指的是响应host或device端发送的数据。 43 | 44 | host | device | note 45 | :-: | :-: | :-: 46 | 0x7f | - | 发送0x7f,单片机收到后会自动匹配波特率。 47 | \- | 0x79(ACK)/0x1F(NACK) | device返回ACK或NACK,表示对host的反应。 48 | 49 | 适配波特率这一步是无条件执行的,执行完这一步之后就可以接收各种指令。 50 | 下面就介绍各个指令的功能和数据协议。 51 | 52 | ## 3、get command 53 | 54 | 在上面已经适配波特率情况下可以执行此指令。 55 | 【指令码】0x00 56 | 【功能】获取stm32里bootloader版本号,以及所有支持的指令代码。 57 | 【数据协议】 58 | 59 | host | device | note 60 | :-: | :-: | :-: 61 | 0x00 + 0xff | - | 62 | \- | 0x79(ACK)/0x1F(NACK) | 63 | \- | N | 1字节,表示下面要接收到的字节数。bootloaderversion字节数 + 所有指令字节数 = N+1 64 | \- | bootloader version | 1字节,如0x21代表2.1版本 65 | \- | 所有支持的指令 | 多个字节,每个字节数据都表示一个支持的指令 66 | \- | 0x79(ACK)/0x1F(NACK) | 指令执行结束后会返回0x79 67 | 68 | ## 4、get version & read protection 69 | 【指令码】0x01 70 | 【功能】获取stm32里bootloader版本号,读取保护状态。 71 | 【数据协议】 72 | 73 | host | device | note 74 | :-: | :-: | :-: 75 | 0x01+0xfe | - | 76 | \- | 0x79(ACK)/0x1F(NACK) | 77 | \- | bootloader version | 78 | \- | 2个字节 | 这两个字节和保护状态有关 79 | \- | 0x79(ACK)/0x1F(NACK) | 80 | 81 | ## 5、get ID command 82 | 【指令码】0x02 83 | 【功能】获取stm32 PID(product ID,不是芯片唯一识别码)。 84 | 【数据协议】 85 | 86 | host | device | note 87 | :-: | :-: | :-: 88 | 0x02+0xfd | - | 89 | \- | 0x79(ACK)/0x1F(NACK) | 90 | \- | N | 1字节,表示下面 PID字节数 - 1 91 | \- | PID | 多字节(上一个字节已指明字节数),先传高位后传低位。我这次用的stm32f103c8t6是2字节。 92 | \- | 0x79(ACK)/0x1F(NACK) | 93 | 94 | ## 6、Erase Memory command 95 | 【指令码】0x43 96 | 【功能】擦除flash,可以全擦或擦除一部分,这里只介绍全擦。 97 | 【数据协议】 98 | 99 | host | device | note 100 | :-: | :-: | :-: 101 | 0x43+0xbc | - | 102 | \- | 0x79(ACK)/0x1F(NACK) | 103 | 0xff+0x00 | \- | 这是全擦指令 104 | \- | 0x79(ACK)/0x1F(NACK) | 105 | 106 | ## 7、Write Memory command 107 | 【指令码】0x31 108 | 【功能】 109 | 写存储器,可以写任意的RAM、flash,我们写程序就用这个。 110 | 【数据协议】 111 | 112 | host | device | note 113 | :-: | :-: | :-: 114 | 0x31+0xCE | - | 115 | \- | 0x79(ACK)/0x1F(NACK) | 116 | addr | - | 4字节,下载地址。用户flash起始地址是0x08000000。**先发高位,后发低位** 117 | addr checksum | - | 1字节,地址的checksum,就是上面4字节数据的异或。 118 | \- | 0x79(ACK)/0x1F(NACK) | 119 | count | - | 1字节,表示后面将要传输的字节数,范围(0, 255]。**字节数 = 这个值+1**,也就是说最大传输256字节。 120 | data | - | 多字节,字节数 = count + 1,最大256字节。**这里下载进去的是bin文件,不是hex。。** 121 | checksum | - | 1字节,上面的data数据,以及数据个数count的checksum。注意这里的checksum包含**数据和个数**。 122 | \- | 0x79(ACK)/0x1F(NACK) | 123 | 124 | 注: 125 | 126 | 1. 对于写flash,用户flash的起始地址是0x08000000。 127 | 2. 对于写flash,这里最多一次写256字节,写一个bin文件需要多次使用此协议写入。 128 | 129 | ## 8、Read Memory command 130 | 【指令码】0x11 131 | 【功能】 132 | 读取stm32内存,可以读取stm32任意地址的RAM、flash等数据。 133 | 我们常在下载完成后把flash内容读取出来验证。 134 | 【数据协议】 135 | 136 | host | device | note 137 | :-: | :-: | :-: 138 | 0x11+0xEE | 0x79(ACK)/0x1F(NACK) | 139 | addr | - | 4字节,下载地址。用户flash起始地址是0x08000000。**先发高位,后发低位** 140 | addr checksum | - | 1字节,地址的checksum,就是上面4字节数据的异或。 141 | \- | 0x79(ACK)/0x1F(NACK) | 142 | count | - | 1字节,将要读取的数据个数,0~255。count+1就是将要读取的字节数,最多读取256字节。 143 | checksum | - | 1字节,count的按位取反。 144 | \- | 0x79(ACK)/0x1F(NACK) | 145 | \- | data | count+1个字节,这就是要读取的数据。 146 | 147 | 注: 148 | 149 | 1. 对于读取flash,用户flash的起始地址是0x08000000。 150 | 2. 一次最多读取256字节,要读取大段内容就重复执行这个读取操作。 151 | 152 | ## 9、Go command 153 | 略。 154 | 155 | # 代码说明 156 | 根据上面的下载协议,封装成了模块,这里介绍本程序结构和模块的使用,以便移植到其他地方。 157 | 158 | ## 程序结构 159 | 160 | **wiringSerial.c wiringSerial.h** 161 | 串口驱动,在树莓派[wiringPi](https://github.com/WiringPi/WiringPi)基础上修改,增加了数据块读写代码,增加了更多设置项。 162 | 这部分驱动在mac、桌面ubuntu、树莓派上都可以使用。 163 | 164 | **stm32isp.c stm32isp.h** 165 | 下载逻辑代码,基于串口驱动,串口的打开、关闭操作也归于这部分控制。 166 | 以上两个部分,serial完全归于stm32isp,外部使用stm32isp时不需要再管串口了。 167 | 168 | **main.c** 169 | 程序交互的实现,调用上面stm32isp接口实现下载。 170 | 171 | 下面着重介绍的是stm32isp部分的接口函数。 172 | 173 | ## stm32isp接口 174 | stm32isp使用前提是串口工作正常。 175 | 176 | ### stm32isp_init 177 | `int stm32isp_init(const char *device, const int baud, const int databits, const int stopbits, const char parity, const int timeout);` 178 | 使用前需要先调用此函数,主要是完成串口初始化(串口的打开和关闭也交给stm32isp模块管理)。 179 | 例:`stm32isp_init("/dev/ttyUSB0", 57600, 8, 1, 'N', 30);` 180 | 注:此驱动测试只有57600和38400两个波特率可以正常下载。 181 | 182 | ### stm32isp_close 183 | `void stm32isp_close(); //成功返回1,失败返回0` 184 | 下载结束后调用此函数,主要是完成串口关闭(串口的打开和关闭也交给stm32isp模块管理)。 185 | 186 | ### stm32isp_sync 187 | `int stm32isp_sync();` 188 | 同步波特率,成功返回1,失败返回0。 189 | 打开串口后第一步就需要sync,和单片机同步波特率。 190 | 191 | ### stm32isp_get_command 192 | `int stm32isp_get_command()` 193 | 获取ID和command列表,信息保存在驱动内部结构体,不输出,但会进行打印信息。成功返回1,失败返回0。 194 | 这一步不是下载必须执行的。 195 | 196 | ### stm32isp_get_ID_command 197 | `int stm32isp_get_ID_command();` 198 | 获取PID,信息保存在驱动内部结构体,不输出,但会进行打印。成功返回1,失败返回0。 199 | 这一步不是下载必须执行的。 200 | 201 | ### stm32isp_erase_all 202 | `int stm32isp_erase_all();` 203 | 全擦flash,成功返回1,失败返回0。 204 | 下载之前先擦除flash。 205 | 206 | ### stm32isp_write_bin 207 | `int stm32isp_write_bin(char *p);` 208 | 传入bin文件路径,写入bin文件到flash,成功返回1,失败返回0。 209 | 注意写入的是bin文件,不是hex文件。 210 | bin文件路径可能由main函数的argv参数传入。 211 | 212 | ### stm32isp_verify 213 | `int stm32isp_verify(char *p);` 214 | 传入bin文件路径,根据bin文件大小读取flash相应大小内容,并把两个比较,验证成功返回1,失败返回0。 215 | 这一步可选,为了保险可下载后验证一下。 216 | 217 | 218 | 219 | 220 | -------------------------------------------------------------------------------- /documents/ad.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicekwell/stm32ISP/d87dfd13400823b68bf76c9c5ca1daa5d4995605/documents/ad.jpg -------------------------------------------------------------------------------- /documents/stm32isp application note.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicekwell/stm32ISP/d87dfd13400823b68bf76c9c5ca1daa5d4995605/documents/stm32isp application note.pdf -------------------------------------------------------------------------------- /include/stm32isp.h: -------------------------------------------------------------------------------- 1 | #ifndef __STM32_H__ 2 | #define __STM32_H__ 3 | 4 | /* 5 | 本驱动基于已经ok的串口驱动,包括串口初始化、关闭、收发、缓冲区操作。 6 | */ 7 | int stm32isp_init(const char *device, const int baud, const int databits, const int stopbits, const char parity, const int timeout); //成功返回1,失败返回0 8 | void stm32isp_close(); 9 | 10 | 11 | int stm32isp_sync(); //同步波特率,成功返回1,失败返回0 12 | int stm32isp_get_command(); //获取ID和command列表,信息保存在驱动内部结构体,不输出,但会进行打印 13 | //成功返回1,失败返回0 14 | int stm32isp_get_ID_command(); //获取PID,信息保存在驱动内部结构体,不输出,但会进行打印 15 | //成功返回1,失败返回0 16 | int stm32isp_erase_all(); //全擦flash,成功返回1,失败返回0 17 | int stm32isp_write_bin(char *p); //传入bin文件路径,写入bin文件到flash,成功返回1,失败返回0 18 | int stm32isp_verify(char *p); //传入bin文件路径,根据bin文件大小读取flash内容,并把两个比较 19 | //验证成功返回1,失败返回0 20 | 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /include/wiringSerial.h: -------------------------------------------------------------------------------- 1 | /* 2 | * wiringSerial.h: 3 | * Handle a serial port 4 | *********************************************************************** 5 | * This file is part of wiringPi: 6 | * https://projects.drogon.net/raspberry-pi/wiringpi/ 7 | * 8 | * wiringPi is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU Lesser General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * wiringPi is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU Lesser General Public License 19 | * along with wiringPi. If not, see . 20 | *********************************************************************** 21 | */ 22 | 23 | #ifdef __cplusplus 24 | extern "C" { 25 | #endif 26 | 27 | //extern int serialOpen (const char *device, const int baud) ; //wiringPi默认 28 | /* nicek 29 | 例:serialOpen("/dev/tty.usbserial", 115200, 8, 1, 'N', 30) 30 | 关于timeout: 31 | 1、单位是100ms 32 | 2、缓冲区有数据时,即使数据个数少于read传入的个数,也会立即读取数据后返回,不会延时等待; 33 | 仅当缓冲区里没有任何数据时,才会进行延时等待,等到有数据或者超时后返回。 34 | */ 35 | extern int serialOpen (const char *device, const int baud, const int databits, const int stopbits, const char parity, const int timeout); 36 | extern void serialClose (const int fd) ; 37 | extern void serialFlush (const int fd) ; //清空缓冲区,发送和接收都清空 38 | extern void serialPutchar (const int fd, const unsigned char c) ; //发送一个字符 39 | extern void serialPuts (const int fd, const char *s) ; //发送字符串,s是字符串,不发送字符串结尾'\0' 40 | extern void serialWrite (const int fd, const char *s, const int count); //nicek 写入数据块 41 | extern void serialPrintf (const int fd, const char *message, ...) ; //类似于printf 42 | extern int serialDataAvail (const int fd) ; //检查缓冲区里的数据个数 43 | extern int serialGetchar (const int fd) ; //返回读取的字符 44 | extern int serialRead (const int fd, char *p, const int count); //nicek 读取数据块,写入到p,返回读取到的个数 45 | //如果缓冲区里没有数据,则会阻塞等待,直到有一个数据立马读出返回 46 | //如果缓冲区里有数据n,且ncount,则读出count个数据后返回,缓冲区里有剩余数据 48 | 49 | #ifdef __cplusplus 50 | } 51 | #endif 52 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main(int argc, char *argv[]) 8 | { 9 | if(argc != 3){ 10 | printf("parameter error!\nexample: stm32isp /dev/ttyUSB0 stm32_test.bin\n"); 11 | return 0; 12 | } 13 | 14 | stm32isp_init(argv[1], 57600, 8, 1, 'N', 30); 15 | 16 | printf("syncing..."); 17 | if(stm32isp_sync()) printf("sync ok\n"); 18 | else printf("sync fail\n\n"); 19 | 20 | stm32isp_get_command(); 21 | stm32isp_get_ID_command(); 22 | 23 | printf("erasing flash...\n"); 24 | if(stm32isp_erase_all()) printf("erase flash done\n"); 25 | else printf("erase flash fail\n\n"); 26 | 27 | printf("starting download...\n"); 28 | if(stm32isp_write_bin(argv[2])) printf("download success\n"); 29 | else printf("download fail\n\n"); 30 | 31 | printf("starting verify...\n"); 32 | if(stm32isp_verify(argv[2])) printf("verify success\n"); 33 | else printf("verify fail\n"); 34 | 35 | stm32isp_close(); 36 | return 0; 37 | } 38 | -------------------------------------------------------------------------------- /stm32_test.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicekwell/stm32ISP/d87dfd13400823b68bf76c9c5ca1daa5d4995605/stm32_test.bin -------------------------------------------------------------------------------- /stm32isp.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | static int fd; 7 | 8 | typedef struct { 9 | unsigned char bootloaderversion; //1字节,bootloader版本 10 | unsigned char cmd_count; //支持的所有指令个数 11 | unsigned char cmd[16]; //支持的所有指令 12 | unsigned int PID; //product ID 13 | } stm32info_t; 14 | static stm32info_t stm32info; 15 | 16 | static int waitACK() //等待接收数据,第一个字节如果是0x79则认为ok返回1,如果是0x1f则认为失败返回0 17 | { 18 | while(1){ 19 | if(0 != serialDataAvail(fd)) { 20 | if(0x79 == serialGetchar(fd)) 21 | return 1; 22 | else 23 | return 0; 24 | } 25 | usleep(1000); 26 | } 27 | } 28 | static unsigned char checksum(unsigned char *data, int len) //计算p开始len个字节的checksum,也就是计算异或 29 | { 30 | int i; 31 | unsigned char cs; 32 | cs = 0; 33 | for ( i=0; i>24) & 0xff); 44 | temp[1] = ((addr>>16) & 0xff); 45 | temp[2] = ((addr>>8) & 0xff); 46 | temp[3] = ((addr) & 0xff); 47 | 48 | serialPutchar(fd, 0x31); 49 | serialPutchar(fd, 0xce); 50 | waitACK(); 51 | serialPutchar(fd, temp[0]); 52 | serialPutchar(fd, temp[1]); 53 | serialPutchar(fd, temp[2]); 54 | serialPutchar(fd, temp[3]); 55 | serialPutchar(fd, checksum(temp, 4)); 56 | waitACK(); 57 | //下面发送数据 58 | len1 = (unsigned char)(len - 1); 59 | serialPutchar(fd, len1); 60 | for(i=0;i>24) & 0xff); 76 | temp[1] = ((addr>>16) & 0xff); 77 | temp[2] = ((addr>>8) & 0xff); 78 | temp[3] = ((addr) & 0xff); 79 | 80 | serialPutchar(fd, 0x11); 81 | serialPutchar(fd, 0xEE); 82 | waitACK(); 83 | serialPutchar(fd, temp[0]); 84 | serialPutchar(fd, temp[1]); 85 | serialPutchar(fd, temp[2]); 86 | serialPutchar(fd, temp[3]); 87 | serialPutchar(fd, checksum(temp, 4)); 88 | waitACK(); 89 | //下面发送要读取的字节数 90 | len1 = (unsigned char)(len - 1); 91 | serialPutchar(fd, len1); 92 | serialPutchar(fd, ~len1); 93 | waitACK(); 94 | //下面接收数据 95 | for(i=0;i. 20 | *********************************************************************** 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | #include "wiringSerial.h" 36 | 37 | /* 38 | * serialOpen: 39 | * Open and initialise the serial port, setting all the right 40 | * port parameters - or as many as are required - hopefully! 41 | ********************************************************************************* 42 | */ 43 | 44 | int serialOpen (const char *device, const int baud, const int databits, const int stopbits, const char parity, const int timeout) 45 | { 46 | struct termios options ; 47 | speed_t myBaud ; 48 | int status, fd ; 49 | 50 | switch (baud) 51 | { 52 | case 50: myBaud = B50 ; break ; 53 | case 75: myBaud = B75 ; break ; 54 | case 110: myBaud = B110 ; break ; 55 | case 134: myBaud = B134 ; break ; 56 | case 150: myBaud = B150 ; break ; 57 | case 200: myBaud = B200 ; break ; 58 | case 300: myBaud = B300 ; break ; 59 | case 600: myBaud = B600 ; break ; 60 | case 1200: myBaud = B1200 ; break ; 61 | case 1800: myBaud = B1800 ; break ; 62 | case 2400: myBaud = B2400 ; break ; 63 | case 4800: myBaud = B4800 ; break ; 64 | case 9600: myBaud = B9600 ; break ; 65 | case 19200: myBaud = B19200 ; break ; 66 | case 38400: myBaud = B38400 ; break ; 67 | case 57600: myBaud = B57600 ; break ; 68 | case 115200: myBaud = B115200 ; break ; 69 | case 230400: myBaud = B230400 ; break ; 70 | //nicek: 以下波特率在ubuntu里没问题,但mac下不支持 71 | /* case 460800: myBaud = B460800 ; break ; */ 72 | /* case 500000: myBaud = B500000 ; break ; */ 73 | /* case 576000: myBaud = B576000 ; break ; */ 74 | /* case 921600: myBaud = B921600 ; break ; */ 75 | /* case 1000000: myBaud = B1000000 ; break ; */ 76 | /* case 1152000: myBaud = B1152000 ; break ; */ 77 | /* case 1500000: myBaud = B1500000 ; break ; */ 78 | /* case 2000000: myBaud = B2000000 ; break ; */ 79 | /* case 2500000: myBaud = B2500000 ; break ; */ 80 | /* case 3000000: myBaud = B3000000 ; break ; */ 81 | /* case 3500000: myBaud = B3500000 ; break ; */ 82 | /* case 4000000: myBaud = B4000000 ; break ; */ 83 | 84 | default: 85 | return -2 ; 86 | } 87 | 88 | if ((fd = open (device, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK)) == -1) 89 | return -1 ; 90 | 91 | fcntl (fd, F_SETFL, O_RDWR) ; 92 | 93 | // Get and modify current options: 94 | 95 | tcgetattr (fd, &options) ; 96 | 97 | cfmakeraw (&options) ; 98 | cfsetispeed (&options, myBaud) ; 99 | cfsetospeed (&options, myBaud) ; 100 | 101 | options.c_cflag |= (CLOCAL | CREAD) ; 102 | 103 | //nicek 校验 104 | //options.c_cflag &= ~PARENB ; //wiringPi默认 105 | switch(parity) { 106 | case 'n': //不校验 107 | case 'N': 108 | options.c_cflag &= ~PARENB; 109 | options.c_iflag &= ~INPCK; //enable parity checking 110 | break; 111 | case 'o': //奇校验 112 | case 'O': 113 | options.c_cflag |= PARENB; 114 | options.c_cflag |= PARODD; 115 | options.c_iflag |= INPCK; //disable parity checking 116 | break; 117 | case 'e': //偶校验 118 | case 'E': 119 | options.c_cflag |= PARENB; 120 | options.c_cflag &= ~PARODD; 121 | options.c_iflag |= INPCK; 122 | break; 123 | case 's': //space校验 124 | case 'S': 125 | options.c_cflag &= ~PARENB; 126 | options.c_cflag &= ~CSTOPB; 127 | break; 128 | } 129 | 130 | //nicek 停止位 131 | //options.c_cflag &= ~CSTOPB ; // wiringPi默认 132 | switch(stopbits) { 133 | case 1: 134 | options.c_cflag &= ~CSTOPB; 135 | break; 136 | case 2: 137 | options.c_cflag |= ~CSTOPB; 138 | break; 139 | } 140 | 141 | options.c_cflag &= ~CSIZE ; 142 | 143 | //nicek 数据位 144 | //options.c_cflag |= CS8 ; // wiringPi默认 145 | switch (databits) { 146 | case 5: 147 | options.c_cflag |= CS5 ; 148 | break; 149 | case 6: 150 | options.c_cflag |= CS6 ; 151 | break; 152 | case 7: 153 | options.c_cflag |= CS7 ; 154 | break; 155 | case 8: 156 | options.c_cflag |= CS8 ; 157 | break; 158 | } 159 | 160 | options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG) ; 161 | options.c_oflag &= ~OPOST ; 162 | 163 | options.c_cc [VMIN] = 0 ; 164 | //nicek timeout 165 | //options.c_cc [VTIME] = 100 ; // Ten seconds (100 deciseconds) 166 | options.c_cc [VTIME] = timeout; 167 | 168 | tcsetattr (fd, TCSANOW, &options) ; 169 | 170 | ioctl (fd, TIOCMGET, &status); 171 | 172 | status |= TIOCM_DTR ; 173 | status |= TIOCM_RTS ; 174 | 175 | ioctl (fd, TIOCMSET, &status); 176 | 177 | usleep (10000) ; // 10mS 178 | 179 | return fd ; 180 | } 181 | 182 | 183 | /* 184 | * serialFlush: 185 | * Flush the serial buffers (both tx & rx) 186 | ********************************************************************************* 187 | */ 188 | 189 | void serialFlush (const int fd) 190 | { 191 | tcflush (fd, TCIOFLUSH) ; 192 | } 193 | 194 | 195 | /* 196 | * serialClose: 197 | * Release the serial port 198 | ********************************************************************************* 199 | */ 200 | 201 | void serialClose (const int fd) 202 | { 203 | close (fd) ; 204 | } 205 | 206 | 207 | /* 208 | * serialPutchar: 209 | * Send a single character to the serial port 210 | ********************************************************************************* 211 | */ 212 | 213 | void serialPutchar (const int fd, const unsigned char c) 214 | { 215 | write (fd, &c, 1) ; 216 | } 217 | 218 | 219 | /* 220 | * serialPuts: 221 | * Send a string to the serial port 222 | ********************************************************************************* 223 | */ 224 | 225 | void serialPuts (const int fd, const char *s) 226 | { 227 | write (fd, s, strlen (s)) ; 228 | } 229 | 230 | /* 231 | nicek: 写入指定长度数据 232 | */ 233 | void serialWrite(const int fd, const char *s, const int count) 234 | { 235 | write(fd, s, count); 236 | } 237 | 238 | /* 239 | * serialPrintf: 240 | * Printf over Serial 241 | ********************************************************************************* 242 | */ 243 | 244 | void serialPrintf (const int fd, const char *message, ...) 245 | { 246 | va_list argp ; 247 | char buffer [1024] ; 248 | 249 | va_start (argp, message) ; 250 | vsnprintf (buffer, 1023, message, argp) ; 251 | va_end (argp) ; 252 | 253 | serialPuts (fd, buffer) ; 254 | } 255 | 256 | 257 | /* 258 | * serialDataAvail: 259 | * Return the number of bytes of data avalable to be read in the serial port 260 | ********************************************************************************* 261 | */ 262 | 263 | int serialDataAvail (const int fd) 264 | { 265 | int result ; 266 | 267 | if (ioctl (fd, FIONREAD, &result) == -1) 268 | return -1 ; 269 | 270 | return result ; 271 | } 272 | 273 | 274 | /* 275 | * serialGetchar: 276 | * Get a single character from the serial device. 277 | * Note: Zero is a valid character and this function will time-out after 278 | * 10 seconds. 279 | ********************************************************************************* 280 | */ 281 | 282 | int serialGetchar (const int fd) 283 | { 284 | uint8_t x ; 285 | 286 | if (read (fd, &x, 1) != 1) 287 | return -1 ; 288 | 289 | return ((int)x) & 0xFF ; 290 | } 291 | 292 | /* 293 | nicek: 读取指定长度 294 | */ 295 | int serialRead( const int fd, char *p, const int count) 296 | { 297 | int len; 298 | len = read(fd, p, count); 299 | return len; 300 | } 301 | 302 | --------------------------------------------------------------------------------