筆者之前用STM32的ADC外設通過DMA通道來傳輸數據,通常有兩種方法,一個是直接通過DMA通道傳輸數據,二是通過定時器觸發。相較而言,后者在實際中比較常使用,因為ADC讀取傳感器數據需要一段時間,通常我們不會讓處理器一直讓ADC外設讀取數據,而是根據ADC的讀取時間和實際項目所需來使用定時器觸發,有些傳感器如室內溫度我們不需要經常讀取,我們可以200ms讀取一次,在STM32處理器中就很方便了,直接通過設置定時器觸發達到此效果。如果用的處理器沒有這個功能,我們可以通過定時器產生的時隙劃分合適的時間,在需要的時間端允許ADC外設讀取,該做法也是可行的。
下面,列出主要的配置代碼和注意事項:
//ADC配置,紅色為注意
void Adc_Init(void)
{
ADC_InitTypeDef ADC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE );
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //兩個ADC工作在獨立模式
ADC_InitStructure.ADC_ScanConvMode = ENABLE; //掃描多通道模式
// ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; //連續轉換模式
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; // 定時器觸發不使能連續
//禁止外部觸發轉換模式,軟件觸發
//ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_CC2;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //AD數據右對齊
ADC_InitStructure.ADC_NbrOfChannel = 2; //順序進行規則轉換的ADC通道的數目
ADC_Init(ADC1, &ADC_InitStructure);
//規則采樣通道次序與采樣時間
ADC_RegularChannelConfig(ADC1, ADC_Channel_17, 2, ADC_SampleTime_239Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_16, 1, ADC_SampleTime_239Cycles5);
ADC_TempSensorVrefintCmd(ENABLE); //使能內部溫度傳感器
ADC_DMACmd(ADC1, ENABLE); //ADC命令,和DMA關聯
ADC_Cmd(ADC1, ENABLE); //使能ADC
ADC_ResetCalibration(ADC1); //復位ADC校準寄存器
while(ADC_GetResetCalibrationStatus(ADC1)); //等待校準寄存器復位完成
ADC_StartCalibration(ADC1); //開始ADC校準
while(ADC_GetCalibrationStatus(ADC1)); //等待校準完成
//ADC_SoftwareStartConvCmd(ADC1, ENABLE); //注釋掉軟件啟動AD轉換
ADC_ExternalTrigConvCmd(ADC1, ENABLE); //使能外部定時器觸發
}
//DMA配置
void MYDMA_Config(void)
{
DMA_InitTypeDef DMA_InitStruct;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE );
//DMA init; Using DMA1 channel 1
DMA_DeInit(DMA1_Channel1); //復位DMA1的第1通道
DMA_InitStruct.DMA_PeripheralBaseAddr = (u32)&ADC1->DR; //DMA對應的外設基地址
DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; //轉換結果16bits
DMA_InitStruct.DMA_MemoryBaseAddr = (u32)ADC_TempValue;
DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC; //DMA的轉換模式是SRC模式,外設to內存
DMA_InitStruct.DMA_M2M = DMA_M2M_Disable; //M2M模式禁止,memory to memory
DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; //DMA搬運的數據16bits
//接收一次數據后,目標內存地址后移,用來采集多個數據的
DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
//接收一次數據后,設備地址是否后移
DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
//轉換模式:常用循環緩存模式。如果M2M開啟了,則這個模式失效
//另一種是Normal模式:不循環,僅一次DMA
//DMA_InitStruct.DMA_Mode = DMA_Mode_Circular;
DMA_InitStruct.DMA_Mode = DMA_Mode_Normal;
DMA_InitStruct.DMA_Priority = DMA_Priority_High; //DMA優先級,高
DMA_InitStruct.DMA_BufferSize = 8; //DMA緩存大小
DMA_Init(DMA1_Channel1,&DMA_InitStruct);
DMA_ClearITPendingBit(DMA1_IT_TC1);
DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE); //開啟DMA1CH1中斷
DMA_Cmd(DMA1_Channel1, ENABLE);
}
//定時器配置,設置想要的觸發頻率
void TIM2_Int_Init(u16 arr,u16 psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //時鐘使能
//定時器TIM3初始化
TIM_TimeBaseStructure.TIM_Period = arr; //設置在下一個更新事件裝入活動的自動重裝載寄存器周期的值
TIM_TimeBaseStructure.TIM_Prescaler =psc; //設置用來作為TIMx時鐘頻率除數的預分頻值
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //設置時鐘分割:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上計數模式
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); //根據指定的參數初始化TIMx的時間基數單位
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 1000;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
//TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE); //使能指定的TIM2中斷,允許更新中斷 不需要中斷。是用定時器的PWM觸發
TIM_OC2Init(TIM2, & TIM_OCInitStructure);
//中斷優先級NVIC設置
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; //TIM2中斷
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //先占優先級0級
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //從優先級3級
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
NVIC_Init(&NVIC_InitStructure); //初始化NVIC寄存器
TIM_Cmd(TIM2, ENABLE); //使能TIMx
}
//中斷優先級配置
void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //優先級分組4,所有位均用于搶占優先級
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
|