打印
[匠人手记]

《两轮小车DIY》之《搞定ADC》(动态更新)

[复制链接]
3819|8
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
程序匠人|  楼主 | 2009-3-19 23:37 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
沙发
程序匠人|  楼主 | 2009-3-19 23:40 | 只看该作者

艳照来了

LCD上显示的是:

X,Y及各自后面的3位数据,分别代表两个轴向的AD值。

其中:

第1行是未经过滤波的采样值
第2行是滤波之后的采样值

使用特权

评论回复
板凳
程序匠人|  楼主 | 2009-3-19 23:50 | 只看该作者

昨天遇到一件比较郁闷的事情

就是上次辛辛苦苦焊好的MMA7260居然莫名其妙坏掉了,幸亏匠人还有一片备用片。今天又发挥了一次三级焊工的技能,重新换了一片。

但愿老天佛祖上帝真主保佑,这颗独苗别再坏了。

南无偶弥陀佛;
南无上帝耶稣;
南无玉皇大帝;
南无真主阿拉;
南无圣母玛丽;
南无S T 意法;
南无飞思卡尔;
南无程序匠人;

阿门!

使用特权

评论回复
地板
程序匠神| | 2009-3-20 00:28 | 只看该作者

应该喊:南无程序匠神!

使用特权

评论回复
5
程序匠人|  楼主 | 2009-3-20 22:53 | 只看该作者

今天把内部温度传感器即内部参考电压两个通道玩了一下

已经可以显示温度了——不过这个功能与小车功能无关,纯属跑题。呵呵。

感觉DMA的功能很实用。可以让CPU腾出时间去做其它事情。

俺现在是4个通道(2个外部,2个内部)轮流扫描检测,并且为每个通道开辟100个存放位置。到时候取个平均就好了。

感觉真是奢侈。欧耶!

下面给出几个程序片段 :




//--------------------------------------------------------
//主函数
//--------------------------------------------------------
int main(void)
{
#ifdef DEBUG
  debug();
#endif


    //================
    //主程序初始化段
    //================

  RCC_Configuration();            //系统时钟配置
  NVIC_Configuration();          //中断配置
  GPIO_Configuration();            //IO口(GPIO)配置
  DMA_Configuration();            //DMA配置
  ADC_Configuration();            //ADC配置
  SysTick_Configuration();  //SysTick初始化设置

  Init_LCD() ;                    //LCD初始化函数
  //DisplayString_LCD(0,1,"CXJR21ic");


    //================
    //主程序循环段
    //================
  while(1)
  {
        SysTick_Delay(300);                                //延时

        X_AVR = Average(AD_Value,0);            //计算 X轴加速度采样滤波值
         //Y_AVR = Average(AD_Value,1);            //计算 Y轴加速度采样滤波值
         TEMP_AVR = Average(AD_Value,2);        //计算 内部温度传感器采样滤波值
         VREF_AVR = Average(AD_Value,3);        //计算 内部参考电压采样滤波值

        GetTemp();                                                //根据ADC结果计算温度
        
        Disp_X_AVR();                                            //显示X轴加速度采样滤波值
         Disp_Temp_Value();                                //显示温度值
        //Disp_XY_ADR();                                        //显示XY轴加速度采样值

        //Disp_XY_AVR();                                        //显示XY轴加速度采样滤波值

    //Disp_Inside_ADR();                          //显示内部通道采样值

  }
}



//--------------------------------------------------------
//双字节中位值平均滤波
//功能:    将队列中数据减去最大值和最小值,然后求平均值(小数四舍五入)
//入口:    QUEUE        =队列
//    nChannel        =序列号
//出口:            =滤波结果(平均值)
//--------------------------------------------------------
u16 Average(vu16 QUEUE[],u8 nChannel) 
{
    u16 max = 0;
    u16 min = 0xFFFF;
    u32 sum = 0;
    u16 i,j;

    for(i=0;i<ADC_Average_n;i++)   //
    {
        j=nChannel+i*ADC_Channel_n;        
        if ( QUEUE[j] > max ) max = QUEUE[j];                //比较并更新最大值
        if ( QUEUE[j] < min ) min = QUEUE[j];          //比较并更新最小值

        sum = sum + QUEUE[j];                //追加到和值

    }
        i = ADC_Average_n - 2;    
        sum = sum - max - min + i/2;
        sum = sum / i;                                    //平均值=(和值-最大值-最小值+n/2)/(队列长度-2)
                                //说明:+(n-2)/2的目的是为了四舍五入
    return ((u16) sum)  ;
    
}

//--------------------------------------------------------
//DMA配置
//功能:    从ADC模块自动读转换结果至内存
//--------------------------------------------------------
void DMA_Configuration(void)
{
    DMA_InitTypeDef DMA_InitStructure;                                                                //定义DMA初始化结构体
    DMA_DeInit(DMA_Channel1);                                                                                    //复位DMA通道1
    DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;                //定义DMA通道外设基地址=ADC1_DR_Address
    DMA_InitStructure.DMA_MemoryBaseAddr = (u32)&AD_Value;                        //定义DMA通道存储器地址
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;                                //指定外设为源地址
    DMA_InitStructure.DMA_BufferSize = ADC_Channel_n*ADC_Average_n;     //定义DMA缓冲区大小(对应于ADC转换序列数量),
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;    //当前外设寄存器地址不变
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                        //当前存储器地址自动递增加1
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;    //定义外设数据宽度16位
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;                    //定义存储器数据宽度16位
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;                                        //DMA通道操作模式=循环模式开启(Buffer写满后,自动回到初始地址开始传输)
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;                                //DMA通道优先级高
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;                                            //禁止DMA通道存储器到存储器传输
    DMA_Init(DMA_Channel1, &DMA_InitStructure);                                                //初始化DMA通道1
    DMA_Cmd(DMA_Channel1, ENABLE);                                                                        //使能DMA通道1
}


//--------------------------------------------------------
//ADC配置
//说明:包括ADC模块配置和自校准,并启动第一次AD转换
//--------------------------------------------------------
void ADC_Configuration(void)
{
    //====ADC模块配置
  ADC_InitTypeDef ADC_InitStructure;                                                                    //定义ADC初始化结构体
  ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;                                    //ADC1和ADC2工作在独立模式
  ADC_InitStructure.ADC_ScanConvMode = ENABLE;                                                //使能扫描
  ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;                                  //ADC转换工作在连续模式
  ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;    //有软件控制转换
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;                            //转换数据右对齐
  ADC_InitStructure.ADC_NbrOfChannel = ADC_Channel_n;                           //设置转换序列长度
  ADC_Init(ADC1, &ADC_InitStructure);                                                                    //初始化ADC1
  ADC_TempSensorVrefintCmd(ENABLE);                                                                        //ADC内置温度传感器使能(要使用片内温度传感器,切忌要开启它)
  //ADC_RegularChannelConfig(ADC1, ADC_Channel_8, 1, ADC_SampleTime_13Cycles5);    //常规转换序列1:通道8
  //ADC_RegularChannelConfig(ADC1, ADC_Channel_9, 2, ADC_SampleTime_13Cycles5);    //常规转换序列2:通道9
  ADC_RegularChannelConfig(ADC1, ADC_Channel_8, 1, ADC_SampleTime_239Cycles5);    //常规转换序列1:通道8
  ADC_RegularChannelConfig(ADC1, ADC_Channel_9, 2, ADC_SampleTime_239Cycles5);    //常规转换序列2:通道9
  ADC_RegularChannelConfig(ADC1, ADC_Channel_16, 3, ADC_SampleTime_239Cycles5);    //常规转换序列3:通道16(内部温度传感器),采样时间>2.2us,(239cycles)
  ADC_RegularChannelConfig(ADC1, ADC_Channel_17, 4, ADC_SampleTime_239Cycles5);    //常规转换序列4:通道17(内部参考电压),采样时间>2.2us,(239cycles)
  ADC_Cmd(ADC1, ENABLE);                                                                                            //使能ADC1 
  ADC_DMACmd(ADC1, ENABLE);                                                                                        //开启ADC1的DMA支持(要实现DMA功能,还需独立配置DMA通道等参数)
    
  //====ADC自动校准
  ADC_ResetCalibration(ADC1);                                                        //重置ADC1校准寄存器
  while(ADC_GetResetCalibrationStatus(ADC1));                        //等待ADC1校准重置完成
  ADC_StartCalibration(ADC1);                                                        //开始ADC1校准
  while(ADC_GetCalibrationStatus(ADC1));                                //等待ADC1校准完成

    //====启动第一次AD转换
    ADC_SoftwareStartConvCmd(ADC1, ENABLE);                             //使能ADC1,开始转换
                                                                                                              //因为已经配置好了DMA,接下来AD自动连续转换,结果自动保存在AD_Value处   
  
}


//--------------------------------------------------------
//根据ADC结果计算温度
//入口:    TEMP_AVR=温度传感器采样值
//            VREF_AVR=参考电压采样值
//出口:    Temp_Value=温度值
//--------------------------------------------------------
//温度值计算公式如下:
//          V25 - VSENSE
//  T(℃) = ------------  + 25℃
//           Avg_Slope
//其中:
//      V25:              温度传感器在25℃时 的输出电压,典型值1.43 V。
//      VSENSE:        温度传感器的当前输出电压.    VSENSE = 温度传感器采样值(TEMP_AVR) * 参考电压(1.2V) / 参考电压采样值(VREF_AVR)
//      Avg_Slope:    温度传感器输出电压和温度的关联参数,典型值4.3 mV/℃。
//--------------------------------------------------------
void GetTemp(void)
{
    s32 i;
  i = (143 - TEMP_AVR * 120 / VREF_AVR)*10000/43 + 2500; 

    if (i<0) Temp_Value=0;
    else if (i>9999) Temp_Value=99;
    else Temp_Value = i /100;
}  

使用特权

评论回复
6
tmstd| | 2009-6-1 18:13 | 只看该作者

好玩啊

使用特权

评论回复
7
totoko163| | 2009-9-3 09:44 | 只看该作者
up

使用特权

评论回复
8
ZCDS| | 2009-12-24 21:31 | 只看该作者
留爪

使用特权

评论回复
9
lost1421| | 2009-12-28 17:17 | 只看该作者
不要留了,没戏了!

使用特权

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

本版积分规则

734

主题

11156

帖子

676

粉丝