本帖最后由 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文件里定义,如果有更高优先级的任务就绪了,则执行一次任务切换
}
|
|