[STM32MP1] 【STM32MP135F-DK测评】编写串口应用程序

[复制链接]
 楼主| xinmeng_wit 发表于 2024-2-25 21:09 | 显示全部楼层 |阅读模式
<
本帖最后由 xinmeng_wit 于 2024-2-25 21:14 编辑

上一篇(https://bbs.21ic.com/icview-3360172-1-1.html)中已经完成了UART的设备树的配置和编译,以及使用shell脚本进行简单的UART的数据的收发测试,这一篇将编写应用程序来发送UART数据,同时打印接收到的UART数据。
本篇将使用termios 结构体以及相关的api来实现对串口的设置、数据的写入和读取。

1、编写应用代码
先是调用serial_open函数对UART硬件进行初始化,其中设备名(串口号)需要作为参数传入,其它参数已经被程序指定死了,不可传入。默认波特率9600,8N1。
初始化完成后,进入while(1)循环中,循环发送字符串Hello STM32MP135F-DK,同时查看串口是否有消息接收到,若有则通过控制台打印出来。
uart.c源代码如下:

  1. #include <stdio.h> /* Standard input/output */

  2. #include <fcntl.h> /* File control definitions */

  3. #include <string.h>

  4. #include <stdlib.h>

  5. #include <termio.h> /* POSIX terminal control definitions */

  6. #include <sys/time.h> /* Time structures for select() */

  7. #include <unistd.h> /* POSIX Symbolic Constants */

  8. #include <assert.h>

  9. #include <errno.h> /* Error definitions */

  10. #include <sys/mman.h>

  11. #define CMSPAR 010000000000

  12. #define SERIAL_FLUSH_TX1

  13. #define SERIAL_FLUSH_RX2

  14. #define SERIAL_PARITY_NO 0

  15. #define SERIAL_PARITY_ODD 1

  16. #define SERIAL_PARITY_EVENT 2

  17. #define SERIAL_PARITY_MARK 3

  18. #define SERIAL_PARITY_SPACE 4

  19. #define SERIAL_STOPBIT_ONE 1

  20. #define SERIAL_STOPBIT_TWO 2

  21. static int serial_fd = -1;

  22. struct termios old_tios;

  23. static void serial_print_buf(unsigned char *buf,int len) /* 打印输出 */

  24. {

  25. int i;

  26. for(i=0;i<len;i++)

  27. printf("%02X ",buf[i]);

  28. printf("\n");

  29. }

  30. char *get_serial_dev_name(char *serial_name) /* 获取串口名称 */

  31. {

  32. if (strcasecmp(serial_name, "/dev/ttySTM1") == 0)

  33. return serial_name;

  34. else

  35. return "NULL";

  36. }

  37. static int termios_init(struct termios *tios,int baud,int parity,int data_bits,int stop_bits) //串口 传入波特率,校验位,数据位,停止位。

  38. {

  39. speed_t baud_rate;

  40. if (tios == NULL)

  41. return -1;

  42. tios->c_line = 0;

  43. tios->c_cc[VMIN ] = 0;

  44. tios->c_cc[VTIME] = 0;

  45. /* configure the input modes... */

  46. tios->c_iflag = IGNBRK | IGNPAR | INPCK;

  47. /* configure the output modes... */

  48. tios->c_oflag = 0; /* enable implementation-defined output processing */

  49. /* configure the control modes... */

  50. tios->c_cflag = CREAD | CLOCAL;

  51. if (data_bits == 5) //对传入的数据位进行判断

  52. tios->c_cflag |= CS5;

  53. else if (data_bits == 6)

  54. tios->c_cflag |= CS6;

  55. else if (data_bits == 7)

  56. tios->c_cflag |= CS7;

  57. else if (data_bits == 8)

  58. tios->c_cflag |= CS8;

  59. else

  60. return -1;

  61. if (stop_bits == 1)//对传入的停止位进行判断

  62. tios->c_cflag &=~ CSTOPB;

  63. else if (stop_bits == 2)

  64. tios->c_cflag |= CSTOPB;

  65. else

  66. return -1;

  67. if(parity == 0)//校验位: 0:无校验 1:奇校验 2:偶校验 3:mark parity 4:space parity

  68. { /* none */

  69. tios->c_cflag &=~ PARENB;

  70. tios->c_cflag &=~ PARODD;

  71. }

  72. else if(parity == 2)

  73. { /* even */

  74. tios->c_cflag |= PARENB;

  75. tios->c_cflag &=~ PARODD;

  76. }

  77. else if(parity == 1)

  78. { /* odd */

  79. tios->c_cflag |= PARENB;

  80. tios->c_cflag |= PARODD;

  81. }

  82. else if (parity == 3)/* 2008.12.17 add for support mark and space parity */

  83. {

  84. /* mark */

  85. tios->c_cflag |= PARENB;

  86. tios->c_cflag |= CMSPAR;

  87. tios->c_cflag |= PARODD;

  88. }

  89. else if (parity == 4)

  90. {

  91. /* space */

  92. tios->c_cflag |= PARENB;

  93. tios->c_cflag |= CMSPAR;

  94. }

  95. else

  96. return -1;

  97. /* configure the local modes... */

  98. tios->c_lflag = 0; /* enable implementation-defined input processing */

  99. /* Set the baud rate */

  100. switch(baud)//对传入的波特率进行判断

  101. {

  102. case 110:

  103. baud_rate = B110;

  104. break;

  105. case 300:

  106. baud_rate = B300;

  107. break;

  108. case 600:

  109. baud_rate = B600;

  110. break;

  111. case 1200:

  112. baud_rate = B1200;

  113. break;

  114. case 2400:

  115. baud_rate = B2400;

  116. break;

  117. case 4800:

  118. baud_rate = B4800;

  119. break;

  120. case 9600:

  121. baud_rate = B9600;

  122. break;

  123. case 19200:

  124. baud_rate = B19200;

  125. break;

  126. case 38400:

  127. baud_rate = B38400;

  128. break;

  129. case 57600:

  130. baud_rate = B57600;

  131. break;

  132. case 115200:

  133. baud_rate = B115200;

  134. break;

  135. case 230400:

  136. baud_rate = B230400;

  137. break;

  138. case 460800:

  139. baud_rate = B460800;

  140. break;

  141. case 576000:

  142. baud_rate = B576000;

  143. break;

  144. case 921600:

  145. baud_rate = B921600;

  146. break;

  147. default:

  148. return -1;

  149. }

  150. if ((cfsetispeed(tios, baud_rate) < 0) ||(cfsetospeed(tios, baud_rate) < 0))

  151. return -1;

  152. return 0;

  153. }

  154. //return serial fd, error return -1

  155. int serial_open(char *serial_name, int baud,int parity,int data_bits,int stop_bits,int timeout) //打开串口

  156. {

  157. struct termios settings;

  158. int fd;

  159. char *serial_dev_name;

  160. if (serial_fd >= 0)

  161. return 0;

  162. if (termios_init(&settings, baud,parity,data_bits,stop_bits) < 0)

  163. return 0;

  164. serial_dev_name = get_serial_dev_name(serial_name);

  165. if (serial_dev_name == NULL)

  166. {

  167. fprintf(stderr, "invalid serial name:%s\n", serial_name);

  168. return 0;

  169. }

  170. if((fd = open(serial_dev_name, O_RDWR | O_NOCTTY | O_NDELAY))< 0)

  171. return 0;

  172. if(tcgetattr(fd, &old_tios) < 0)

  173. {

  174. close(fd);

  175. return 0;

  176. }

  177. if(tcsetattr(fd, TCSANOW, &settings) < 0)

  178. {

  179. close(fd);

  180. return 0;

  181. }

  182. serial_fd = fd;

  183. return 1;

  184. }

  185. int serial_close() //关闭串口

  186. {

  187. if (serial_fd < 0)

  188. return 0;

  189. tcsetattr(serial_fd, TCSANOW, &(old_tios));

  190. close(serial_fd);

  191. serial_fd = -1;

  192. return 1;

  193. }

  194. int serial_flush(int flag)

  195. {

  196. if (serial_fd < 0)

  197. return 0;

  198. if (flag == SERIAL_FLUSH_TX)

  199. tcflush(serial_fd,TCOFLUSH);

  200. else if (flag == SERIAL_FLUSH_RX)

  201. tcflush(serial_fd,TCIFLUSH);

  202. else if (flag == (SERIAL_FLUSH_RX|SERIAL_FLUSH_TX) )

  203. tcflush(serial_fd,TCIOFLUSH);

  204. return 1;

  205. }

  206. int serial_write(char *buf,size_t size) //串口写入数据

  207. {

  208. int writesize = 0;

  209. writesize = write(serial_fd,buf,size);

  210. //printf("serial write: length=%d, packet: ",writesize);

  211. //serial_print_buf(buf,writesize);

  212. return writesize;

  213. }

  214. int serial_read(char *buf,size_t size) //串口读取数据

  215. {

  216. int readsize = 0;

  217. if (size<=0)

  218. return 0;

  219. readsize = read(serial_fd,buf,size);

  220. printf("serial read: length=%d, packet: ",readsize);

  221. serial_print_buf(buf, readsize);

  222. return readsize;

  223. }

  224. //return 1: poll ok, 0: timeout, -1: error

  225. int serial_poll(int timeout)

  226. {

  227. int fd = serial_fd;

  228. fd_set rfds;

  229. struct timeval tv;

  230. int sel_res;

  231. FD_ZERO(&rfds);

  232. FD_SET(fd, &rfds);

  233. tv.tv_sec = timeout/1000;

  234. tv.tv_usec = (timeout % 1000)*1000;

  235. return select(fd + 1, &rfds, NULL,NULL,&tv);

  236. }

  237. int main(int argc, char *argv[])

  238. {

  239. int fd;

  240. char send_buffer[100] = "Hello STM32MP135F-DK\r\n";

  241. char recv_buffer[100];

  242. int i, ret;

  243. if (argc != 2) //需要传入串口对应的设备名

  244. {

  245. fprintf(stderr, "usage:serialtest com_port\n");

  246. return -1;

  247. }

  248. ret = serial_open(argv[1], 9600, SERIAL_PARITY_NO, 8, SERIAL_STOPBIT_ONE, 1000); //调用上面封装好的打开串口函数 传入设备名,波特率,校验位,数据位,停止位以及超时时间

  249. if (ret == 0)//打开失败

  250. {

  251. fprintf(stderr, "open serial failed\n");

  252. return -1;

  253. }

  254. /*

  255. for(i=0; i<20; i++)

  256. {

  257. send_buffer[i] = i;

  258. }

  259. */

  260. while(1)

  261. {

  262. serial_write(send_buffer, strlen(send_buffer)); //写入数据

  263. //read

  264. while (serial_poll(1000)>0)//当另一端传入数据时会接收到数据

  265. {

  266. serial_read(recv_buffer, sizeof(recv_buffer));

  267. }

  268. }

  269. serial_close();

  270. return 0;

  271. }

Makeifle文件:

  1. uart:uart.c

  2. $(CC) -Iinclude -o uart uart.c

  3. clean:

  4. rm *.o uart


2、编译应用程序
使用make命令来进行编译
75e6504061d5125359ddecbf199677ee
编译之前记得source一下编译环境
  1. source SDK/environment-setup-cortexa7t2hf-neon-vfpv4-ostl-linux-gnueabi

编译完成后会生成uart的可执行文件
9189dcfa095ccb34696b22c148d39232
将uart可执行文件上传到开发板后,进入到开发板终端执行uart程序:
  1. root@stm32mp1:~# ./uart /dev/ttySTM1

c959cce51bc3a7596aef4de355427b0b
此时,串口助手上已经能看到开发板发出来的消息了:
0ba46b0a40c470bb03ac24011981910a
然后,通过串口助手发送消息给开发板,开发板会将收到的消息打印在终端上:
串口终端发送字符串1234,开发板终端打印的消息如下:
9dc78c78311bb766bd54f120690f3d3e
以上,可以用看出得到的结果符合程序预期的运行结果,测试完成。

您需要登录后才可以回帖 登录 | 注册

本版积分规则

70

主题

276

帖子

2

粉丝
快速回复 在线客服 返回列表 返回顶部