打印
[uCOS/RTOS]

请教关于ucos 的STM32 ADC采样问题

[复制链接]
4736|17
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
V一舟|  楼主 | 2013-9-8 08:29 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 V一舟 于 2013-9-11 16:35 编辑

各位大神,小弟初次接触ucos,遇到了一个棘手的问题,还请各位相助。
我若吧ADC采样的转换模式换成连续转换模式,整个系统都不能正常运行;若换为单次转换模式,那么系统可以运行,但采集不到AD的值,或许是因为制转换一次。
adc初始化源码
#include "includes.h"

                  
//初始化ADC,开启通道CH-0                                                                                                                                          
void  Adc_Init(void)
{         
        ADC_InitTypeDef ADC_InitStructure;
        GPIO_InitTypeDef GPIO_InitStructure;
        DMA_InitTypeDef DMA_InitStructure;

        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_ADC1, ENABLE );          //使能ADC1通道时钟
   /* Enable DMA clock */
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

        
        //PA0 作为模拟通道输入引脚                        
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;                //模拟输入引脚
        GPIO_Init(GPIOA, &GPIO_InitStructure);        

        /* DMA channel1 configuration ----------------------------------------------*/
        //使能DMA
        DMA_DeInit(DMA1_Channel1);
        DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;                                    //DMA通道1的地址
        DMA_InitStructure.DMA_MemoryBaseAddr = (u32)&ADC_ConvertedValue;                    //DMA传送地址
        DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;                                                    //外设作为数据传输的来源
        DMA_InitStructure.DMA_BufferSize = 100;                                                                            //传送内存大小,100个16位
        DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;                                 //外设地址寄存器不递增
        DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                                            //传送内存地址递增
        DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;                //ADC1转换的数据是16位
        DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;                                //传送的目的地址是16位宽度
        DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;                                                                        //循环
        DMA_InitStructure.DMA_Priority = DMA_Priority_High;                                                                //设置DMA通道优先级高
        DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
        DMA_Init(DMA1_Channel1, &DMA_InitStructure);

        /* 允许DMA1通道1传输结束中断 */
        DMA_ITConfig(DMA1_Channel1,DMA_IT_TC, ENABLE);

        //使能DMA通道1
        DMA_Cmd(DMA1_Channel1, ENABLE);

        ADC_DeInit(ADC1);  //将外设 ADC1 的全部寄存器重设为缺省值

        ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;                           //ADC工作模式:ADC1工作在独立模式
        ADC_InitStructure.ADC_ScanConvMode = DISABLE;                              //模数转换工作在单通道模式
        ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;                         //模数转换工作在连续转换模式(就是这个配置,若改为单次转换模式,则可以                                                                                                                            工作
        ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;        //转换由软件而不是外部触发启动
        ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;                    //ADC数据右对齐
        ADC_InitStructure.ADC_NbrOfChannel = 1;                                   //顺序进行规则转换的ADC通道的数目
        ADC_Init(ADC1, &ADC_InitStructure);                                      //根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器   

        //配置ADC时钟 ,72M/8=9,ADC最大时间不能超过14M
        RCC_ADCCLKConfig(RCC_PCLK2_Div6);   
        //ADC1 规则通道配置
          ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_55Cycles5);          //通道0采样时间 55.5周期

        ADC_DMACmd(ADC1,ENABLE); //使能ADC1_DMA

        ADC_Cmd(ADC1, ENABLE);        //使能指定的ADC1
        
        ADC_ResetCalibration(ADC1);        //重置指定的ADC1的校准寄存器
         
        while(ADC_GetResetCalibrationStatus(ADC1));        //获取ADC1重置校准寄存器的状态,设置状态则等待
        
        ADC_StartCalibration(ADC1);                //开始指定ADC1的校准状态

        while(ADC_GetCalibrationStatus(ADC1));                //获取指定ADC1的校准程序,设置状态则等待
         
        ADC_SoftwareStartConvCmd(ADC1, ENABLE);                //使能指定的ADC1的软件转换启动功能
        
}                          
app.c中程序
#define GLOBALS

#include "includes.h"

//数据变量定义
float ADC_ConvertedValueLocal;

//建立信号量
OS_EVENT* Com1_SEM;
OS_EVENT* Com1_MBOX;
OS_EVENT* ADC_SEM;


static  OS_STK App_TaskStartStk[APP_TASK_START_STK_SIZE];
static  OS_STK Task_Com1Stk[Task_Com1_STK_SIZE];
static  OS_STK Task_LedStk[Task_Led_STK_SIZE];
static  OS_STK Task_ADCStk[Task_ADC_STK_SIZE];
/*
*********************************************************************************************************
*                                      LOCAL FUNCTION PROTOTYPES
*********************************************************************************************************
*/

static  void APP_TaskCreate(void);
static  void APP_TaskStart(void* p_arg);
static  void Task_Com1(void* p_arg);
static  void Task_Led(void* p_arg);
static  void Task_ADC(void* p_arg);

extern char *itoa(int value, char *string, int radix);



/*主函数*/
/*
*********************************************************************************************************
*                                                main()
*
* Description : This is the standard entry point for C code.  It is assumed that your code will call
*               main() once you have performed all necessary initialization.
*
* Argument : none.
*
* Return   : none.
*********************************************************************************************************
*/

int main(void)
{

   //禁止CPU中断
   //CPU_IntDis();

   //UCOS 初始化
   OSInit();                                                   /* Initialize "uC/OS-II, The Real-Time Kernel".         */

   //硬件平台初始化
   BSP_Init();                                                 /* Initialize BSP functions.  */

        
   /*向串口1发送开机字符*/
   /*
   USART_OUT(USART1,"*********RTOS系统测试程序************\r\n");
   USART_OUT(USART1,"*                                   *\r\n");            
   USART_OUT(USART1,"*          串口测试                 *\r\n");  
   USART_OUT(USART1,"*                                   *\r\n");                     
   USART_OUT(USART1,"*       基于 uCOSII2.86             *\r\n");              
   USART_OUT(USART1,"*                                   *\r\n");                     
   USART_OUT(USART1,"*************************************\r\n");
   USART_OUT(USART1,"\r\n");
   USART_OUT(USART1,"\r\n");            
   */
   //建立主任务, 优先级最高  建立这个任务另外一个用途是为了以后使用统计任务
   OSTaskCreate( (void (*) (void *)) APP_TaskStart,                                                         //指向任务代码的指针
                 (void *) 0,                                                                                              //任务开始执行时,传递给任务的参数的指针
                 (OS_STK *) &App_TaskStartStk[APP_TASK_START_STK_SIZE - 1],            //分配给任务的堆栈的栈顶指针   从顶向下递减
                 (INT8U) APP_TASK_START_PRIO);                                                                    //分配给任务的优先级


       //ucos的节拍计数器清0    节拍计数器是0-4294967295    对于节拍频率100hz时, 每隔497天就重新计数
       OSTimeSet(0);                                                            
            OSStart();                                                  /* Start multitasking (i.e. give control to uC/OS-II).  */
                                                                                                                           /* Start multitasking (i.e. give control to uC/OS-II).  */
     return (0);
}



/*建立系统任务*/
static void APP_TaskStart(void *p_arg)
{
  (void)p_arg;                 // 'p_arg' 并没有用到,防止编译器提示警告

  /*使能ucos的统计任务*/
  #if(OS_TASK_STAT_EN>0)
     OSStatInit();             //统计任务初始化函数
  #endif

  /*调用其他任务建立的函数*/
  APP_TaskCreate();

   while(1)
   {
         
          /*1秒1次循环*/
          OSTimeDlyHMSM(0, 0,1,0);
         
   }
}


/*建立其他任务的函数集合*/
static void APP_TaskCreate(void)
{

   ADC_SEM=OSSemCreate(0);                                 //建立ADC采样信号量,在中断函数里同步

   Com1_SEM=OSSemCreate(1);                                //建立串口1中断的信号量
   Com1_MBOX=OSMboxCreate((void *) 0);                     //建立串口1中断的消息邮箱


   //串口1接收及发送任务---------------------------------------------------------   
   OSTaskCreateExt( Task_Com1,                                                                          //指向任务代码的指针
                                           (void *)0,                                                                          //任务开始执行时,传递给任务的参数的指针
                                        (OS_STK *)&Task_Com1Stk[Task_Com1_STK_SIZE-1],//分配给任务的堆栈的栈顶指针   从顶向下递减
                                        Task_Com1_PRIO,                                                                  //分配给任务的优先级
                                        Task_Com1_PRIO,                                                                  //预备给以后版本的特殊标识符,在现行版本同任务优先级
                                        (OS_STK *)&Task_Com1Stk[0],                                          //指向任务堆栈栈底的指针,用于堆栈的检验
                    Task_Com1_STK_SIZE,                                                          //指定堆栈的容量,用于堆栈的检验
                    (void *)0,                                                                          //指向用户附加的数据域的指针,用来扩展任务的任务控制块
                    OS_TASK_OPT_STK_CHK|OS_TASK_OPT_STK_CLR);          //选项,指定是否允许堆栈检验,是否将堆栈清0,任务是否要进行浮点运算等等。
   //LED1 闪烁任务------------------------------------------------------
   OSTaskCreateExt( Task_Led,
                    (void *)0,
                                    (OS_STK *)&Task_LedStk[Task_Led_STK_SIZE-1],
                                    Task_Led_PRIO,
                                        Task_Led_PRIO,
                                        (OS_STK *)&Task_LedStk[0],
                    Task_Led_STK_SIZE,
                    (void *)0,
                                    OS_TASK_OPT_STK_CHK|OS_TASK_OPT_STK_CLR);
   //ADC采集任务------------------------------------------------------
   OSTaskCreateExt( Task_ADC,
                    (void *)0,
                                    (OS_STK *)&Task_ADCStk[Task_ADC_STK_SIZE-1],
                                    Task_ADC_PRIO,
                                        Task_ADC_PRIO,
                                        (OS_STK *)&Task_ADCStk[0],
                    Task_ADC_STK_SIZE,
                    (void *)0,
                                    OS_TASK_OPT_STK_CHK|OS_TASK_OPT_STK_CLR);

}

/*建立子任务函数*/

//LED1闪烁任务----------------------------------------
static  void Task_Led(void* p_arg)
{
  (void) p_arg;            
   while (1)
   {

      LED1_ON;
      OSTimeDlyHMSM(0, 0, 0, 500);
      LED1_OFF;
      OSTimeDlyHMSM(0, 0, 0, 500);

          USART_OUT(USART1,"\r\n LED任务运行正常! \r\n");
         
          OSTimeDly(1);        
   }
}


//ADC数据采集与转换任务·
static void Task_ADC(void* p_arg)
{
  INT8U err;

  (void) p_arg;

  while(1)
  {
     OSSemPend(ADC_SEM,0,&err);

         if(ADC_TIMEOUT>1000)
                {                        
                  //1秒采样一次
          ADC_TIMEOUT=0;

                  ADC_ConvertedValueLocal=(float)ADC_ConvertedValue/4096*3.3;
        
          USART_OUT(USART1,"\r\n ADC1 通道1的值: ");
              printf("%d",ADC_ConvertedValue );
          USART_OUT(USART1,"\r\n ADC1 电压的值: ");
              printf("%f",ADC_ConvertedValueLocal );
              USART_OUT(USART1,"\r\n");
          USART_OUT(USART1,"\r\n");
              
                }                                
     OSTimeDly(1);
  }
}

//串口任务
//++++++++++++COM1处理任务++++++++++++++++++++++++++
static  void Task_Com1(void *p_arg)
{   
   INT8U err;
           
   unsigned char * msg;

  (void)p_arg;
                                             
   while(1)
   {
            //OSSemPend(Com1_SEM,0,&err);                                           //等待串口接收指令成功的信号量(方法1)

          msg=(unsigned char *)OSMboxPend(Com1_MBOX,0,&err);                   //等待串口接收指令成功的邮箱信息(方法2)
          //USART_OUT(USART1,&TxBuffer1[0]);
             if(msg[0]=='L'&&msg[1]=='M')
          {
                   USART_OUT(USART1,"\r\n 串口任务正常! \r\n");         
          }
   }
}
中断中程序

/*******************************************************************************
* Function Name  : DMA1_Channel1_IRQHandler
* Description    : This function handles DMA1 Channel 1 interrupt request.
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
extern OS_EVENT* ADC_SEM;
void DMA1_Channel1_IRQHandler(void)
{
           
        OS_CPU_SR  cpu_sr;

    OS_ENTER_CRITICAL();  //保存全局中断标志,关总中断
    OSIntNesting++;                     //中断嵌套
    OS_EXIT_CRITICAL();          //恢复全局中断标志
        
        if(DMA_GetITStatus(DMA1_IT_TC1))                  //转换完成
    {
                   ADC_TIMEOUT++;

                OSSemPost(ADC_SEM);

                USART_OUT(USART1,"\r\n 进入DMA中断 \r\n ");         
                                                        
            DMA_ClearITPendingBit(DMA1_IT_GL1);      //清除中断标志
        }
    OSIntExit();                                 //在os_core.c文件里定义,如果有更高优先级的任务就绪了,则执行一次任务切换                  
}


相关帖子

沙发
airwill| | 2013-9-8 09:33 | 只看该作者
估计是中断过于频繁, 占用太多时间资源, OS 的时间资源严重不足

使用特权

评论回复
板凳
V一舟|  楼主 | 2013-9-8 17:39 | 只看该作者
airwill 发表于 2013-9-8 09:33
估计是中断过于频繁, 占用太多时间资源, OS 的时间资源严重不足

我也感觉是这个问题,但是对于AD来说,最低的采样时间也是纳秒级,看来ucos不适合做这个

使用特权

评论回复
地板
V一舟|  楼主 | 2013-9-8 18:58 | 只看该作者
还请各位出手相助啊,谢谢了

使用特权

评论回复
5
airwill| | 2013-9-8 22:09 | 只看该作者
未必吧, 也许是你的系统设计得不好, 也许还没有了解和用好 OS.

使用特权

评论回复
6
V一舟|  楼主 | 2013-9-9 21:15 | 只看该作者
不要沉下去啊

使用特权

评论回复
7
jack.king| | 2013-9-10 16:40 | 只看该作者
我也想知道

使用特权

评论回复
8
V一舟|  楼主 | 2013-9-10 17:47 | 只看该作者
jack.king 发表于 2013-9-10 16:40
我也想知道

怎么回事呢

使用特权

评论回复
9
杨爱林林| | 2013-9-11 08:43 | 只看该作者
方便的话 工程 上传来

使用特权

评论回复
10
V一舟|  楼主 | 2013-9-11 16:34 | 只看该作者
杨爱林林 发表于 2013-9-11 08:43
方便的话 工程 上传来

好的,劳烦指教一下

使用特权

评论回复
11
V一舟|  楼主 | 2013-9-11 16:36 | 只看该作者
V一舟 发表于 2013-9-11 16:34
好的,劳烦指教一下

文件太大了

使用特权

评论回复
12
hustjitiejun| | 2013-12-14 11:32 | 只看该作者
AD采样不用中断方式,用中断方式,CPU就忙于中断了,还干什么别的事啊?

使用特权

评论回复
13
V一舟|  楼主 | 2013-12-15 10:14 | 只看该作者
hustjitiejun 发表于 2013-12-14 11:32
AD采样不用中断方式,用中断方式,CPU就忙于中断了,还干什么别的事啊?

就是这个问题啊,那应该怎么办呢?设置一个缓冲?

使用特权

评论回复
14
fengdingkusong| | 2013-12-19 10:06 | 只看该作者
USART_OUT(USART1,"\r\n 进入DMA中断 \r\n "); 光这一句就占用了好多时间,在中断中呆的时间太长

使用特权

评论回复
15
negiul| | 2014-1-4 16:43 | 只看该作者
版主,能否指教一下stm32f103zet的DA转换的程序呀!这个自带的怎么配置,还求教一个很低端的问题,三角波输出和方波输出分别用于什么情况啊??

使用特权

评论回复
16
jjjkkk00| | 2014-1-10 08:51 | 只看该作者
中断函数的处理方面着手试试。感觉那边有些。。。。

使用特权

评论回复
17
andyjian| | 2014-1-21 15:48 | 只看该作者
你的程序一直在中断中度过,哈哈,不知道楼主单通道采集时最好不要用DMA

使用特权

评论回复
18
ijcool| | 2015-7-25 09:14 | 只看该作者
正要做ucos的adc采样程序,刚搜罗一下,看到楼主的帖子,感觉起点就这么艰难啊,不知道这部分您解决了没有啊

使用特权

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

本版积分规则

4

主题

21

帖子

0

粉丝