zoukankan      html  css  js  c++  java
  • 【转】发送串口中断

    我将其改为真正的中断发送。
    步骤一:初始化GPIO
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;         //LED1-PC10
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOC, &GPIO_InitStructure);
     
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;          //USART1 TX
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;    //复用推挽输出
    GPIO_Init(GPIOA, &GPIO_InitStructure);          //A端口
     
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;             //USART1 RX
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;   //复用开漏输入
    GPIO_Init(GPIOA, &GPIO_InitStructure);               //A端口
    12345678910111213
    步骤二:开时钟
    /* Enable USART1, GPIOA, GPIOD and AFIO clocks */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC
                             | RCC_APB2Periph_AFIO, ENABLE);
    123
    在此说明,不用设置RCC_APB2Periph_AFIO也是可以的,也就是在此没有使用复用功能。这两个步骤与查询方式是一样的。
    步骤三:初始化USART1
    USART_InitStructure.USART_BaudRate = 9600;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits = USART_StopBits_2;
    USART_InitStructure.USART_Parity = USART_Parity_No;      //设置奇校验时,通信出现错误
    USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
     /* Configure the USART1 */
    USART_Init(USART1, &USART_InitStructure);
     /* Enable the USART Transmoit interrupt: this interrupt is generated when the
    USART1 transmit data register is empty */
    USART_ITConfig(USART1, USART_IT_TXE, ENABLE);
     /* Enable the USART Receive interrupt: this interrupt is generated when the
      USART1 receive data register is not empty */
    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
     /* Enable USART1 */
    USART_Cmd(USART1, ENABLE);
    12345678910111213141516
    在这里要使能USART1的外设中断,如USART_ITConfig(USART1, USART_IT_TXE, ENABLE);这就是使能发送中断,但发送寄存器空时能产生中断。
    步骤四:编写中断函数
    #define TxBufferSize1   (countof(TxBuffer1) - 1)
    #define RxBufferSize1   (countof(TxBuffer1) - 1)
    #define countof(a)   (sizeof(a) / sizeof(*(a)))      //表示数组a中元素的个数
     
    uint8_t TxBuffer1[] = "USART Interrupt Example: This is USART1 DEMO";
    uint8_t RxBuffer1[RxBufferSize1],rec_f;
    __IO uint8_t TxCounter1 = 0x00;
    __IO uint8_t RxCounter1 = 0x00;
    uint8_t NbrOfDataToTransfer1 = TxBufferSize1;
    uint8_t NbrOfDataToRead1 = RxBufferSize1;
     
     
    /*串口中断服务程序*/
    void USART1_IRQHandler(void)
    {
      unsigned int i;
      /*接收中断*/
      if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
      {  
        /* Read one byte from the receive data register */
        RxBuffer1[RxCounter1++] = USART_ReceiveData(USART1);
        if(RxCounter1 == NbrOfDataToRead1)  //接收数据达到需要长度,则将数据复制到发送数组中,并置标志
        {                    
          /* Disable the USART1 Receive interrupt */
          //USART_ITConfig(USART1, USART_IT_RXNE, DISABLE);
            for(i=0; i< RxCounter1; i++) TxBuffer1[i]  = RxBuffer1[i];
            rec_f=1;
            RxCounter1=0;
            TxCounter1=0;
            USART_ITConfig(USART1, USART_IT_TXE, ENABLE);  //打开发送中断,这句是关键
        }
      }
      /*发送中断*/
      if(USART_GetITStatus(USART1, USART_IT_TXE) != RESET)
      { 
     
        USART_SendData(USART1, TxBuffer1[TxCounter1++]);
     
        if(TxCounter1 == NbrOfDataToTransfer1)//发送数据完成
        {  
          USART_ITConfig(USART1, USART_IT_TXE, DISABLE); //关闭发送中断
        }  
      }  
    }
    1234567891011121314151617181920212223242526272829303132333435363738394041424344
    至此程序就结束了。
    我们就会有个疑问,main()只包括前三个步骤的初始化和一个死循环,那么中断又是如何触发的呢,main()的结构如下:
    int main(void)
    {
     /* System Clocks Configuration */
     RCC_Configuration();
     /* NVIC configuration */
     NVIC_Configuration();
     /* Configure the GPIO ports */
     GPIO_Configuration();
     USART_Configuration();
     
     while (1)
     {
     }
    }
    1234567891011121314
    原来是这样的:状态寄存器USART_SR的复位值为0x00C0H, 也就是第七位TXE和第六位TC复位值为1,而TXE=1,表明发送数据寄存器为空, TC=1表明发送已完成。而在USART的设置中有
     USART_ITConfig(USART1, USART_IT_TXE, ENABLE);
     USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
    12
    这两句使能中断,也就是说当TXE=1就会进入中断,所以程序初始化后就能进入中断,执行
    if(USART_GetITStatus(USART1, USART_IT_TXE) != RESET)
     { 
        /* Write one byte to the transmit data register */
          USART_SendData(USART1, TxBuffer[TxCounter++]);
        if(TxCounter == NbrOfDataToTransfer)
        {
          /* Disable the USART1 Transmit interrupt */
          USART_ITConfig(USART1, USART_IT_TXE, DISABLE);
        }
     }
    12345678910
    因此建议的是在初始化时不好启用TXE中断,只在要发送数据(尤其是字符串、数组这样的系列数据)时才启用TXE。在发送完成后立即将其关闭,以免引起不必要的麻烦。
    对于发送,需要注意TXE和TC的差别——这里简单描述一下,假设串口数据寄存器是DR、串口移位寄存器是SR以及TXD引脚TXDpin,其关系是DR->SR->TXDpin。当DR中的数据转移到SR中时TXE置1,如果有数据写入DR时就能将TXE置0;如果SR中的数据全部通过TXDpin移出并且没有数据进入DR,则TC置1。并且需要注意TXE只能通过写DR来置0,不能直接将其清零,而TC可以直接将其写1清零。
    对于发送单个字符可以考虑不用中断,直接以查询方式完成。
    对于发送字符串/数组类的数据,唯一要考虑的是只在最后一个字符发送后关闭发送中断,这里可以分为两种情况:对于发送可显示的字符串,其用0x00作为结尾的,因此在ISR中就用0x00作为关闭发送中断(TXE或者TC)的条件;第二种情况就是发送二进制数据,那就是0x00~0xFF中间的任意数据,就不能用0x00来判断结束了,这时必须知道数据的具体长度。
    来自 http://huangchuanlong.blog.163.com/blog/static/14709020201281921233833/
    ---------------------
    作者:刘Zzr
    来源:CSDN
    原文:https://blog.csdn.net/weixin_43202477/article/details/84848295
    版权声明:本文为博主原创文章,转载请附上博文链接!

  • 相关阅读:
    lua 源码阅读 5.3.5 笔记
    lua 源码阅读 1.1 -> 2.1
    lua 1.0 源码分析 -- 总结
    lua 1.0 源码分析 -- 2 内存回收
    lua 1.0 源码分析 -- 1 lua 的虚拟指令
    protoc-c 阅读笔记
    protoc-c 安装记录
    转前端开发中常用工具函数总结
    sql 设计规范
    web.config文件详解[转]
  • 原文地址:https://www.cnblogs.com/zhangbing12304/p/10881858.html
Copyright © 2011-2022 走看看