打印
[STM32F0]

求 STM32F USART发送中断的例程 。

[复制链接]
1504|13
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
JobShare|  楼主 | 2016-12-17 16:43 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
求 STM32F USART发送中断的例程 。

谢谢!
沙发
yiyigirl2014| | 2016-12-17 18:23 | 只看该作者
例程里接收是中断接收,但是发送中断只是开机的时候将数组里的数中断发送了,其他数据都是在主循环里查询发送的. 我将其改为真正的中断发送。
   步骤一:初始化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端口
步骤二:开时钟
/* Enable USART1, GPIOA, GPIOD and AFIO clocks */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC
                         | RCC_APB2Periph_AFIO, ENABLE);
在此说明,不用设置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);
在这里要使能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  = RxBuffer1;
        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); //关闭发送中断
    }   
  }   
}
至此程序就结束了。
我们就会有个疑问,main()只包括前三个步骤的初始化和一个死循环,那么中断又是如何触发的呢,main()的结构如下:
int main(void)
{
/* System Clocks Configuration */
RCC_Configuration();
/* NVIC configuration */
NVIC_Configuration();
/* Configure the GPIO ports */
GPIO_Configuration();
USART_Configuration();
while (1)
{
}
}
原来是这样的:状态寄存器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);
这两句使能中断,也就是说当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);
    }
}


使用特权

评论回复
评分
参与人数 1威望 +4 收起 理由
JobShare + 4 很给力!
板凳
yiyigirl2014| | 2016-12-17 18:23 | 只看该作者
因此建议的是在初始化时不好启用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来判断结束了,这时必须知道数据的具体长度。

使用特权

评论回复
评分
参与人数 1威望 +4 收起 理由
JobShare + 4 很给力!
地板
JobShare|  楼主 | 2016-12-18 00:15 | 只看该作者
yiyigirl2014 发表于 2016-12-17 18:23
因此建议的是在初始化时不好启用TXE中断,只在要发送数据(尤其是字符串、数组这样的系列数据)时才启用TXE ...

谢谢大侠耐心 、详细的解释 !

学习了

使用特权

评论回复
5
icecut| | 2016-12-18 09:40 | 只看该作者
不会用 stm32cubemx 生成一个?

使用特权

评论回复
6
643757107| | 2016-12-18 12:45 | 只看该作者
什么都生成一个,多麻烦。

使用特权

评论回复
7
JobShare|  楼主 | 2016-12-18 17:17 | 只看该作者
谢谢各位,学习了

使用特权

评论回复
8
yiyigirl2014| | 2016-12-20 23:18 | 只看该作者
还是认真搞懂每个库函数的用处最好

使用特权

评论回复
9
Stannis| | 2016-12-21 21:39 | 只看该作者
stm32cubemx 生成一个?

有条件的调用,或者循环里调用,怎么用cubemx做呢

使用特权

评论回复
10
JobShare|  楼主 | 2016-12-30 17:41 | 只看该作者
yiyigirl2014 发表于 2016-12-17 18:23
例程里接收是中断接收,但是发送中断只是开机的时候将数组里的数中断发送了,其他数据都是在主循环里查询发 ...

再次 拜读 大侠的帖子,茅塞顿开,受益匪浅 !

再次致谢 !

使用特权

评论回复
11
ElectronF0| | 2017-1-1 15:31 | 只看该作者
yiyigirl2014 发表于 2016-12-17 18:23
因此建议的是在初始化时不好启用TXE中断,只在要发送数据(尤其是字符串、数组这样的系列数据)时才启用TXE ...

看帖学习



使用特权

评论回复
12
JobShare|  楼主 | 2017-1-1 15:34 | 只看该作者
yiyigirl2014 发表于 2016-12-17 18:23
例程里接收是中断接收,但是发送中断只是开机的时候将数组里的数中断发送了,其他数据都是在主循环里查询发 ...

谢谢大侠

编译时 报错,找不到原因,还请指点



使用特权

评论回复
13
JobShare|  楼主 | 2017-1-1 15:47 | 只看该作者
yiyigirl2014 发表于 2016-12-17 18:23
例程里接收是中断接收,但是发送中断只是开机的时候将数组里的数中断发送了,其他数据都是在主循环里查询发 ...

编译通过


使用特权

评论回复
14
yiyigirl2014| | 2017-1-6 10:08 | 只看该作者
最后一个问题是什么情况,麻烦也介绍一下啊,哪儿没设置对?

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

298

主题

1418

帖子

5

粉丝