你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32F072在跑UCOS时UART中断服务程序只进去第一次

[复制链接]
haihuang-402384 提问时间:2014-12-17 18:54 /
我跑裸机的时候在中断里面接收到数据就马上发送出来没有问题,但是在Ucos系统下只有第一次进了UART中断服务程序,ucos其它任务照常运行。这是怎么回事?(备注:接收的是GPS模块传过来的数据,然后在任务中串口输出是没问题的,就是中断接收有问题)
中断服务程序如下:
void USART1_IRQHandler(void)
{
        INT8U i = 0;
        OS_CPU_SR  cpu_sr;

       OS_ENTER_CRITICAL();                        
       OSIntNesting++;
       OS_EXIT_CRITICAL();

       while(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET)
        {
        }
        i = USART_ReceiveData(USART1);
        printf("%c",i);
        OSIntExit();
}
初始化那些应该没问题,跑裸机是可以的
下面是初始化程序:
void NvicInit(void)
{
        
      NVIC_InitTypeDef  NVIC_InitStructure;

      NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
      NVIC_InitStructure.NVIC_IRQChannelPriority = 0x00;
      NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
      NVIC_Init(&NVIC_InitStructure);
      NVIC_InitStructure.NVIC_IRQChannel = EXTI0_1_IRQn;
      NVIC_InitStructure.NVIC_IRQChannelPriority = 0x03;
      NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
      NVIC_Init(&NVIC_InitStructure);
}

void UartInit(void)
{
                INT8U i;

        GPIO_InitTypeDef  GPIO_InitStructure;
        USART_InitTypeDef USART_InitStructure;

        RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA   , ENABLE);   // 使能GPIOA端口
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1   , ENABLE); // 使能串口1时钟
   
        GPIO_PinAFConfig(GPIOA ,GPIO_PinSource9, GPIO_AF_1);
        GPIO_PinAFConfig(GPIOA ,GPIO_Pin_10, GPIO_AF_1);                           
/////////////////////////////////////////////////////////////////////////////////////        
        /* PA9==TX PA10-RX  */  

        GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_9 ;                 
        GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF;
        GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
        GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_UP;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOA, &GPIO_InitStructure);

        GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_10 ;
        GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF;
        GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_UP;        
        GPIO_Init(GPIOA , &GPIO_InitStructure);
/////////////////////////////////////////////////////////////////////////////////////

        USART_InitStructure.USART_BaudRate = 9600;                                       
        USART_InitStructure.USART_WordLength = USART_WordLength_8b;                    
        USART_InitStructure.USART_StopBits = USART_StopBits_1;                        
        USART_InitStructure.USART_Parity = USART_Parity_No;                           
        USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
        USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;               
        USART_Init(USART1, &USART_InitStructure);         //串口配置

        USART_ITConfig(USART1, USART_IT_RXNE,ENABLE);//打开中断        
                                
        USART_Cmd(USART1, ENABLE);//使能串口1
        USART_ClearFlag(USART1, USART_FLAG_TC);  
        
}


收藏 评论29 发布时间:2014-12-17 18:54

举报

29个回答
haihuang-402384 回答时间:2014-12-18 18:04:46
安 发表于 2014-12-18 17:12
还是把你的配置代码发一下吧。

void NvicInit(void)
{
        
      NVIC_InitTypeDef  NVIC_InitStructure;

      NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
      NVIC_InitStructure.NVIC_IRQChannelPriority = 0x00;
      NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
      NVIC_Init(&NVIC_InitStructure);
      NVIC_InitStructure.NVIC_IRQChannel = EXTI0_1_IRQn;
      NVIC_InitStructure.NVIC_IRQChannelPriority = 0x03;
      NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
      NVIC_Init(&NVIC_InitStructure);
}

void UartInit(void)
{
                INT8U i;

        GPIO_InitTypeDef  GPIO_InitStructure;
        USART_InitTypeDef USART_InitStructure;

        RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA   , ENABLE);   // 使能GPIOA端口
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1   , ENABLE); // 使能串口1时钟
   
        GPIO_PinAFConfig(GPIOA ,GPIO_PinSource9, GPIO_AF_1);
        GPIO_PinAFConfig(GPIOA ,GPIO_Pin_10, GPIO_AF_1);                           
/////////////////////////////////////////////////////////////////////////////////////        
        /* PA9==TX PA10-RX  */  

        GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_9 ;                 
        GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF;
        GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
        GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_UP;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOA, &GPIO_InitStructure);

        GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_10 ;
        GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF;
        GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_UP;        
        GPIO_Init(GPIOA , &GPIO_InitStructure);
/////////////////////////////////////////////////////////////////////////////////////

        USART_InitStructure.USART_BaudRate = 9600;                                       
        USART_InitStructure.USART_WordLength = USART_WordLength_8b;                    
        USART_InitStructure.USART_StopBits = USART_StopBits_1;                        
        USART_InitStructure.USART_Parity = USART_Parity_No;                           
        USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
        USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;               
        USART_Init(USART1, &USART_InitStructure);         //串口配置

        USART_ITConfig(USART1, USART_IT_RXNE,ENABLE);//打开中断        
                                
        USART_Cmd(USART1, ENABLE);//使能串口1
        USART_ClearFlag(USART1, USART_FLAG_TC);  
        
}
以上是初始化,我单步调试发现执行完  USART_Cmd(USART1, ENABLE);后RXNE标志位就被置位了
haihuang-402384 回答时间:2014-12-18 18:18:18
安 发表于 2014-12-18 17:12
还是把你的配置代码发一下吧。

这是ST的库函数,执行完USARTx->CR1 |= USART_CR1_UE;后标志位就被置位了
void USART_Cmd(USART_TypeDef* USARTx, FunctionalState NewState)
{
  /* Check the parameters */
  assert_param(IS_USART_ALL_PERIPH(USARTx));
  assert_param(IS_FUNCTIONAL_STATE(NewState));
  
  if (NewState != DISABLE)
  {
    /* Enable the selected USART by setting the UE bit in the CR1 register */
    USARTx->CR1 |= USART_CR1_UE;
  }
  else
  {
    /* Disable the selected USART by clearing the UE bit in the CR1 register */
    USARTx->CR1 &= (uint32_t)~((uint32_t)USART_CR1_UE);
  }
}
看汇编代码如下:
0x080021B6 4770      BX       lr
   403:   if (NewState != DISABLE)
   404:   {
   405:     /* Enable the selected USART by setting the UE bit in the CR1 register */
0x080021B8 2900      CMP      r1,#0x00
0x080021BA D004      BEQ      0x080021C6
   406:     USARTx->CR1 |= USART_CR1_UE;
   407:   }
   408:   else
   409:   {
   410:     /* Disable the selected USART by clearing the UE bit in the CR1 register */
0x080021BC 6802      LDR      r2,[r0,#0x00]
0x080021BE 2301      MOVS     r3,#0x01
0x080021C0 431A      ORRS     r2,r2,r3
0x080021C2 6002      STR      r2,[r0,#0x00]
0x080021C4 E003      B        0x080021CE
   411:     USARTx->CR1 &= (uint32_t)~((uint32_t)USART_CR1_UE);
   412:   }
0x080021C6 6802      LDR      r2,[r0,#0x00]
0x080021C8 0852      LSRS     r2,r2,#1
0x080021CA 0052      LSLS     r2,r2,#1
0x080021CC 6002      STR      r2,[r0,#0x00]
   413: }
haihuang-402384 回答时间:2014-12-18 10:51:02
安 发表于 2014-12-18 09:45
中断中不要写死循环,用if来判断,并且要清除串口标志位。

OSIntEnter();   

F0系列好像跟其他系列不一样,我都是先在裸机上测试的,裸机下情况:一开始我也是用if来判断标志位,if(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) != RESET)
{
      i = USART_ReceiveData(USART1);
      printf("%c",i);
}
至于清除标志位数据手册上面是这么说的:In single buffer mode, clearing the RXNE bit is performed by a software read to the USARTx_RDR register. 那么我读完寄存器标志位也就清除了。然而上述程序跑裸机状态下是不行的,然后我看了摩尔吧枫叶老师的例程是这么写的:
while(USART_GetFlagStatus(F072RB_COM, USART_FLAG_RXNE) == RESET);//等待接收为空
     Uart_buf[0] = (unsigned char)(USART_ReceiveData(F072RB_COM)); // 接收单个字符
他用一个while阻塞到数据接收完,但是我看数据手册并没有说接受完RENE位会被清除,但我试着用他的方法,还真成功接收然后发送出来了。这点我百思不得其解,F0怎么跟其他的有这样的差别。但是移植到操作系统下就出现问题了,只进去一次中断
haihuang-402384 回答时间:2014-12-18 08:54:35
自己顶一下
废鱼 回答时间:2014-12-18 09:45:18
中断中不要写死循环,用if来判断,并且要清除串口标志位。

OSIntEnter();   
              
  if(USART_GetITStatus(USART1, USART_IT_RXNE) !=RESET)
  {
    ch =USART_ReceiveData(USART1);
    USART_ClearITPendingBit(USART1, USART_IT_RXNE);  
  }
   OSIntExit();  
haihuang-402384 回答时间:2014-12-18 10:53:44
安 发表于 2014-12-18 09:45
中断中不要写死循环,用if来判断,并且要清除串口标志位。

OSIntEnter();   

测试表明那个while并不是死循环,状态位会被清除,然后往下执行
废鱼 回答时间:2014-12-18 11:29:22
这里就怕会产生死循环,是个隐性问题。下次再接收时,发生什么情况?退出中断以后,对应的寄存器是否发生了变化?
小贾-370388 回答时间:2014-12-18 11:55:00
In single buffer mode, clearing the RXNE bit is performed by a software read to the USARTx_RDR register,说的是在single buffer 模式 是在软件读USARTx_RDR 的时候产生的清楚RXNE 位,while(USART_GetFlagStatus(F072RB_COM, USART_FLAG_RXNE) == RESET);//这句话应该是当有数据的时候RXNE置位1这时才读取读取完自动会清除 USART_FLAG_RXNE,就会跳出循环,并不是循环等待接受,跟IF 是一个意思。为什么你上面写的是!= RESET啊,只是没有接收到数据的意思啊
haihuang-402384 回答时间:2014-12-18 13:55:40
安 发表于 2014-12-18 11:29
这里就怕会产生死循环,是个隐性问题。下次再接收时,发生什么情况?退出中断以后,对应的寄存器是否发生了 ...

下次不会再进中断了,系统的几个任务都还正常运行,看寄存器RX使能位开着没问题,但是RXNE中断标志位一直没置位,RDR寄存器也一直是0。还有我定义了一个全局数组变量,然后如果用这个数组来存数据的话会发生段错误,所以后来就用了个i来接收,然后调试的时候会看到那个全局变量数组里面的值一直在变化,除了初始化一次后,我又没对它进行操作,这是怎么回事
rdr.png
rxie.png
rxne.png
haihuang-402384 回答时间:2014-12-18 13:58:03
小贾-370388 发表于 2014-12-18 11:55
In single buffer mode, clearing the RXNE bit is performed by a software read to the USARTx_RDR regis ...

之前逻辑乱了,是寄存器接收完数据后才会往下执行,我刚用if来接收,在裸机状态下也可以了,就是跑操作系统时不行
wamcncn 回答时间:2014-12-18 14:08:39
中断服务程序中,前后加上OSIntEnter();OSIntExit();
如果不行,是不是中断任务切换程序出错.
haihuang-402384 回答时间:2014-12-18 14:19:58
wambob 发表于 2014-12-18 14:08
中断服务程序中,前后加上OSIntEnter();OSIntExit();
如果不行,是不是中断任务切换程序出错. ...

都有加进去的
123.png
废鱼 回答时间:2014-12-18 14:25:46
把printf去掉试试。你确定他走到了OSINTEXIT了吗?
wamcncn 回答时间:2014-12-18 14:43:36


while循环体,后面难道不用" ;  "
haihuang-402384 回答时间:2014-12-18 14:44:36
安 发表于 2014-12-18 14:25
把printf去掉试试。你确定他走到了OSINTEXIT了吗?

printf去掉也一样,确定走到OSINTEXIT了,还有虽然第一次能进中断,但是读到的数据是0,RDR寄存器值是0
osintexit.png
haihuang-402384 回答时间:2014-12-18 14:46:13
wambob 发表于 2014-12-18 14:43
while循环体,后面难道不用" ;  "

while下面有{},跟;效果一样,个人习惯,以前会把;号看漏了,所以现在都用{}
12下一页
关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版