已经可以显示温度了——不过这个功能与小车功能无关,纯属跑题。呵呵。
感觉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; } |