一、什么事串口?

  大家常说串口,其实串口有很多种UART,SPI,IIC都是串口,一般大家口中的串口就是UART(Universal Asynchronous Receiver/Transmitter),STM32上集成了UART的控制器,所以我们通过简单的配置就可以实现UART通信的功能。当然光有控制器可以在单板间通信,但大部分的应用场景都是需要远距离的抗干扰传输,这时就需要做电平转换,,目前工业上常用的串口屏,串口透传zigbee,诸如此类的设备都会用到标准的串行接口,所以单板上一般会加一个收发器,来实现电平转换,常用的串行接口就是大家常说的232,485,422等。

对于STM32来说不同的接口控制方法基本类似(就两线制来说),485会多一条读写的控制引脚,因为它是半双工,不能同时读写。

二、怎样使用它?

1.串口外设使能,GPIO使能

  RCC_APB2PeriphClockCmd();

2.串口复位

  USART_DeInit();

3.GPIO模式设置

  GPIO_Init();

  GPIO_PinAFConfig();

4.串口参数初始化

  USART_Init();

5.开启中断并初始化NVIC  

  NVIC_Init();

  USART_ITConfig();

6.使能串口

  UART_Cmd();

7.编写中断处理函数

  USARTx_IRQHandler();

8.串口数据收发

  void USART_SendData();

  u8 USART_ReceiveData();

贴一个配置代码

这是串口控制器结构体

  1. typedef struct Com_Manager
  2. {
  3. u8 Status;
  4. u8 Send_Buf[256];
  5. u16 TxByte_Counter;
  6. u16 Stop_Byte;
  7. u8 Recv_Buf[256];
  8. u16 RxByte_Counter;
  9. u16 OverTime_cnt;
  10. }Com_Manager;

函数实现

  1. void InitUart4(u32 bdr)
  2. {
  3. GPIO_InitTypeDef GPIO_InitStructure;
  4. USART_InitTypeDef USART_InitStructure;
  5. NVIC_InitTypeDef NVIC_InitStructure;
  6.  
  7. RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC,ENABLE);
  8. RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE,ENABLE);
  9. RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4,ENABLE);//IO时钟UART时钟不用说一定都要开启先
  10.  
  11. GPIO_PinAFConfig(GPIOC,GPIO_PinSource10,GPIO_AF_UART4);
  12. GPIO_PinAFConfig(GPIOC,GPIO_PinSource11,GPIO_AF_UART4);//F2系列必须有这一句去开启IO的复用功能
  13. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
  14. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  15. GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  16. GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
  17. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  18. GPIO_Init(GPIOC,&GPIO_InitStructure);
  19. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
  20. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  21. GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
  22. GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
  23. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  24. GPIO_Init(GPIOC,&GPIO_InitStructure);
  25. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
  26. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
  27. GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  28. GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
  29. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  30. GPIO_Init(GPIOE,&GPIO_InitStructure);
  31. UART4_DIR_RX();//这里哦那个
  32.  
  33. USART_DeInit(UART4);
  34. USART_InitStructure.USART_BaudRate = bdr;
  35. USART_InitStructure.USART_WordLength = USART_WordLength_8b;
  36. USART_InitStructure.USART_StopBits = USART_StopBits_1;
  37. USART_InitStructure.USART_HardwareFlowControl =USART_HardwareFlowControl_None;
  38. USART_InitStructure.USART_Parity = USART_Parity_No;
  39. USART_InitStructure.USART_Mode = USART_Mode_Tx|USART_Mode_Rx;
  40. USART_Init(UART4,&USART_InitStructure);//UART配置
  41.  
  42. NVIC_InitStructure.NVIC_IRQChannel = UART4_IRQn;
  43. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  44. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  45. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  46. NVIC_Init(&NVIC_InitStructure);//NVIC配置
  47.  
  48. USART_ITConfig(UART4,USART_IT_RXNE,ENABLE);//可以查参考手册中关于串口中断的部分,RXNE指的是接收完成中断,每当接收到一个字节就进一次中断。
  49. USART_Cmd(UART4,ENABLE);//启动UART
  50. }
  51. void UART4_IRQHandler()//UART USART要注意区分
  52. {
  53. if((USART_GetITStatus(UART4,USART_IT_RXNE))&&((Com[4].Status&0x06) == 0x00))
  54. {
  55. //建立接收
  56. Com[4].Status |= COM_RECEIVING;
  57. Com[4].Recv_Buf[Com[4].RxByte_Counter] = USART_ReceiveData(UART4);
  58. Com[4].RxByte_Counter++;
  59. Com[4].OverTime_cnt = 0;
  60. if(Com[4].RxByte_Counter > 255)
  61. {
  62. Com[4].RxByte_Counter = 0;
  63. Com[4].Status = COM_RECVFULL;//没想好怎么处理
  64. }
  65. }
  66. }
  67. u8 Drv_Uart_Async_Send(Com_Manager* port,u8* send_buf,u16 buf_size)
  68. {
  69. if((buf_size < 256)&&((port->Status&0x03) == 0x00))
  70. {
  71. //建立发送
  72. port->Status |= COM_SENDING;
  73. port->Stop_Byte = buf_size;
  74. port->TxByte_Counter = 0;
  75. memcpy(port->Send_Buf,send_buf,buf_size);
  76. return 1;
  77. }
  78. else
  79. {
  80. //错误类型分类返回
  81. return 0;
  82. }
  83. }
  84. u16 Drv_Uart_Async_Recv(Com_Manager* port,u8 *recv_buf)
  85. {
  86. u16 counter_saver;
  87.  
  88. if((port->Status&COM_RECVCOMPLETE) == COM_RECVCOMPLETE)
  89. {
  90. if(port->RxByte_Counter > 0)
  91. {
  92. counter_saver = port->RxByte_Counter;
  93. memcpy(recv_buf,port->Recv_Buf,port->RxByte_Counter);
  94. port->RxByte_Counter = 0;
  95. port->OverTime_cnt = 0;
  96. port->Status &= ~COM_RECVCOMPLETE;
  97. return counter_saver;
  98. }
  99. else
  100. {
  101. return 0;
  102. }
  103. }
  104. else
  105. {
  106. return 0;
  107. }
  108. }

发送这里用到了定时器,我用了50us来刷新是否有新建的发送任务及正在发送的任务,累计500us没有收到数据认为接收完成。

  1. void Drv_Uart_50us_do()
  2. {
  3. //Com2循环发送处理************************************************************
  4. if((Com[2].Status&COM_SENDING) == COM_SENDING)
  5. {
  6. if(USART_GetFlagStatus(USART2,USART_FLAG_TC) != RESET)
  7. {
  8. UART2_DIR_TX();
  9. USART_SendData(USART2,Com[2].Send_Buf[Com[2].TxByte_Counter++]);
  10. if(Com[2].TxByte_Counter > Com[2].Stop_Byte)
  11. {
  12. UART2_DIR_RX();//非常重要 坑了我一天 发送完必须复位RE 否则进不了接收中断
  13. Com[2].Status &= ~COM_SENDING;
  14. Com[2].TxByte_Counter = 0;
  15. Com[2].Stop_Byte = 0;
  16. }
  17. }
  18. }
  19. //Com2接收超时处理
  20. else if((Com[2].Status&COM_RECEIVING) == COM_RECEIVING)
  21. {
  22. Com[2].OverTime_cnt++;
  23. if(Com[2].OverTime_cnt >= 10)
  24. {
  25. Com[2].Status |= COM_RECVCOMPLETE;
  26. Com[2].Status &= ~COM_RECEIVING;//5ms仍未接收到数据认为接收完成
  27. }
  28. }
  29. }

我这里用了一种状态处理机制,来保证485的半双工正常工作,简单来说就是收的时候不能发送发的时候不能接收,收发互斥。

但是这样做存在一个问题就是如果接受的数据没有及时处理,那么会造成一个死锁,接下来优化考虑用堆栈来接收数据,把接收到的数据压入栈,需要读的时候弹栈。

【STM32】串口收发驱动Drv_Uart|学习笔记的更多相关文章

  1. 驱动开发学习笔记. 0.07 Uboot链接地址 加载地址 和 链接脚本地址

    驱动开发学习笔记. 0.07 Uboot链接地址 加载地址 和 链接脚本地址 最近重新看了乾龙_Heron的<ARM 上电启动及 Uboot 代码分析>(下简称<代码分析>) ...

  2. 基于STM32的USB枚举过程学习笔记

    源:基于STM32的USB枚举过程学习笔记 基于STM32的USB枚举过程学习笔记(一) 基于STM32的USB枚举过程学习笔记(二) 基于STM32的USB枚举过程学习笔记(三) 基于STM32的U ...

  3. stm32串口收发导致的死机

    stm32串口收发导致的死机 很久以前有偶尔遇到过串口死机的情况,那是当时的我写出来的代码自己都觉得有问题,也就没注意.用了stm32做项目以后也就没遇到过了,今天做了个高压测试,每5ms定时发送一次 ...

  4. 驱动开发学习笔记. 0.04 linux 2.6 platform device register 平台设备注册 1/2 共2篇

    驱动开发读书笔记. 0.04  linux 2.6 platform device register 平台设备注册  1/2 共2篇下面这段摘自 linux源码里面的文档 : Documentatio ...

  5. 驱动开发学习笔记. 0.02 基于EASYARM-IMX283 烧写uboot和linux系统

    驱动开发读书笔记. 0.02 基于EASYARM-IMX283 怎么烧写自己裁剪的linux内核?(非所有arm9通用) 手上有一块tq2440,但是不知道什么原因,没有办法烧boot进norflas ...

  6. 驱动开发学习笔记. 0.06 嵌入式linux视频开发之预备知识

    驱动开发读书笔记. 0.06  嵌入式linux视频开发之预备知识 由于毕业设计选择了嵌入式linux视频开发相关的项目,于是找了相关的资料,下面是一下预备知识 UVC : UVC,全称为:USB v ...

  7. 驱动开发学习笔记. 0.05 linux 2.6 platform device register 平台设备注册 2/2 共2篇

    驱动开发读书笔记. 0.05 linux 2.6 platform device register 平台设备注册 2/2 共2篇 下面这段摘自 linux源码里面的文档 : 内核版本2.6.22Doc ...

  8. 驱动开发学习笔记. 0.01 配置arm-linux-gcc 交叉编译器

    驱动开发读书笔记. 0.01 配置arm-linux-gcc 交叉编译器 什么是gcc: 就像windows上的VS 工具,用来编译代码,具体请自己搜索相关资料 怎么用PC机的gcc 和 arm-li ...

  9. 基于STM32的USB枚举过程学习笔记(转)

    之前使用ST官方的库以及网络的资料,完成了使用USB HID类进行STM32和PC机的通讯.由于其他原因并没有深入的分析,虽然实现了功能,但是关于USB设备的枚举,以及具体的通讯方式都没有清晰的概念, ...

  10. stm32串口通信实验,一点笔记

    第一次深入学习stm32,花了好长时间才看懂代码(主要是C语言学习不够深入),又花了段时间自己敲了一遍,然后比对教程,了解了利用中断来串口通信的设置方法. 板子是探索版f407,本实验工程把正点原子库 ...

随机推荐

  1. 关于hbulider开发工具微信小程序请求跨域

    问题描述: 1.thinkphp设置了跨域请求设置 2.接口在浏览器模式正常请求 3.微信小程序请求显示跨域 解决方案:

  2. RDD编程练习

    一.filter,map,flatmap练习: 1.读文本文件生成RDD lines 2.将一行一行的文本分割成单词 words 3.全部转换为小写 4.去掉长度小于3的单词 5.去掉停用词 6.练习 ...

  3. [整合] 解决 Dell T640 安装显卡后风扇转速不降低

    最近实验室的dell T640服务器安装了新的GPU.但是安装后发现,风扇太吵了,于是开始着手解决风扇转速过高的问题. 试过ipmi,但是不好用. 最后发现使用racadm可以让服务器重新安静下来. ...

  4. seqsever 查询多个表的条数,并以列的形式展现

    select sum(a) a,sum(b) b,sum(c) c,SUM(d) d,sum(a1) a1,sum(b1) b1,sum(c1) c1,SUM(d1) d1 from( select ...

  5. MNIST数据集output with shape [1, 28, 28] doesn't match the broadcast shape [3, 28, 28]

    transform = transforms.Compose([ transforms.ToTensor(), transforms.Lambda(lambda x: x.repeat(3,1,1)) ...

  6. sheet.getLastRowNum()获取行数不准的问题

    // 获得总共有多少行int rowNum = 0;//存在样式的空行.会被统计进来.所以主要的问题是要判断是否是空行.for (int num = 1; num <= sheet.getLas ...

  7. List循环问题

    list循环时的问题,报错,称找不到该字段属性,原因如下: 1.字段名与toString里不匹配: 2.首字母大写了: 原回答:https://blog.csdn.net/qq_42671193/ar ...

  8. python经典例题

    [程序1] 题目:有1.2.3.4个数字,能组成多少个互不相同且无重复数字的三位数?都是多少? num_list=[] cou=0 for i in range(1,5): for j in rang ...

  9. [SSH-1]publickey,gssapi-keyex,gssapi-with-mic

    实际上,是有两个不同的原因的,它们都会造成这个报错. 原因1)client端私钥文件权限太大 解决方法:chmod 400 ~/.ssh/id_rsa  #如果是RSA算法的话,私钥生成时默认叫id_ ...

  10. lua如何转化为exe

    在这里下载    https://wwn.lanzout.com/iIS9d07rpesh 然后用cmd到 下载的盘:\luapack\luapack\bin\Debug 然后glue.exe srl ...