使用定时器二进行PWM输出,用来触发ADC的采样,采样结果放入DMA中,自己写的代码,调式过可以用的,管理员觉得可以就加精吧

2019-10-15 00:28发布

  /*
  以下代码使用TIM2定时输出PWM波形,每个PWM周期触发ADC的开启,为了避免DMA 中断 一直发生,影响主函数的运行,我使用了定时器控制ADC的方式,
  注意一下ADC模式与DMA 模式的设置,这里我就不写注释了,代码里面都有;
  这是我项目里面的一部分代码,也许变量或头文件定义不能通过,每个函数都是直接复制过来的,
  可以直接运行,希望对大家有帮助
*/

/*
* ADC.h
*/
#ifndef ADC_H__
#define ADC_H__

#include"stm32f10x.h"

#define ADC_CHANNEL_NUM 5      // 采样通道
#define ADC_SAMPLE_NUM 1       // 采样次数

extern vu16 gvu16AdcValue[ADC_CHANNEL_NUM][ADC_SAMPLE_NUM];
extern vu8 gvu8AdcReady;

void ADC_Initialize(void);

#endif //

////////////////////////////////////////////////////////////////////////////////////
/*
* ADC.c
* 说明:使用定时器二进行PWM输出,用来触发ADC的采样,采样结果放入DMA中
*/
#include"stm32f10x.h"
#include"ADC.h"
#include"stdlib.h"
#include"stdio.h"
#include"string.h"

#define ADC_IT_ENABLE 0
#define DMA_ENABLE 1

vu16 gvu16AdcValue[ADC_CHANNEL_NUM][ADC_SAMPLE_NUM];
vu8 gvu8AdcReady = 0;

void ADC_Initialize(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;
    ADC_InitTypeDef  ADC_InitStructure;
    DMA_InitTypeDef DMA_InitStructure;

    RCC_ADCCLKConfig(RCC_PCLK2_Div6);  // MHZ
    #if DMA_ENABLE
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
    #endif
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOC, ENABLE);

    memset((void *)&gvu16AdcValue[0][0], 0, sizeof(gvu16AdcValue));

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_5;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
    GPIO_Init(GPIOC, &GPIO_InitStructure);                                //PC

    #if DMA_ENABLE
    // 设置 ADC 的DMA 功能并设置其中断
    /* Enable DMA1 channel1 IRQ Channel */
    NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;                                                //抢占优先级低级
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;                                                                        //响应优先级高级
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    DMA_DeInit(DMA1_Channel1);
    DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&ADC1->DR;
    DMA_InitStructure.DMA_MemoryBaseAddr = (u32)&gvu16AdcValue[0][0];               //数据地址
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
    DMA_InitStructure.DMA_BufferSize = ADC_CHANNEL_NUM * ADC_SAMPLE_NUM;                                                //DMA通道数量 * DMA数据
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
    DMA_Init(DMA1_Channel1, &DMA_InitStructure);

    /* Enable DMA1 Channel6 Transfer Complete interrupt */
    DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE);

    /* Enable DMA1 channel1 */
    DMA_Cmd(DMA1_Channel1, ENABLE);
    #endif

    #if ADC_IT_ENABLE
    NVIC_InitStructure.NVIC_IRQChannel = ADC1_2_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
    #endif

    ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
    ADC_InitStructure.ADC_ScanConvMode = ENABLE;
    ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_CC2;
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
    ADC_InitStructure.ADC_NbrOfChannel = ADC_CHANNEL_NUM;                                                //通道数量
    ADC_Init(ADC1, &ADC_InitStructure);

    //ADC检测数据结构为:(高压电压检测,高压电流检测,高压过压检测,高压温度检测,温度辅助检测)
    ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_239Cycles5);
    ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 2, ADC_SampleTime_239Cycles5);
    ADC_RegularChannelConfig(ADC1, ADC_Channel_12, 3, ADC_SampleTime_239Cycles5);
    ADC_RegularChannelConfig(ADC1, ADC_Channel_13, 4, ADC_SampleTime_239Cycles5);
    ADC_RegularChannelConfig(ADC1, ADC_Channel_15, 5, ADC_SampleTime_239Cycles5);

    #if ADC_IT_ENABLE
    ADC_ITConfig(ADC1, ADC_IT_EOC, ENABLE);
    #endif

    #if DMA_ENABLE
    /* Enable ADC1_DMA */
    ADC_DMACmd(ADC1, ENABLE);
    #endif

    /* Enable ADC1 */
    ADC_Cmd(ADC1, ENABLE);

    /* Enable ADC1 reset calibration register */
    ADC_ResetCalibration(ADC1);

    /* Check the end of ADC1 reset calibration register */
    while (ADC_GetResetCalibrationStatus(ADC1));

    /* Start ADC1 calibration */
    ADC_StartCalibration(ADC1);

    /* Check the end of ADC1 calibration */
    while (ADC_GetCalibrationStatus(ADC1));

    ADC_ExternalTrigConvCmd(ADC1, ENABLE);

}

// 使用DMA 采集数据
void DMA1_Channel1_IRQHandler(void)
{
    u16 CurrDataCounterEnd;
    static u8 cur = 0;
    u8 i;

    /* Test on DMA1 Channel6 Transfer Complete interrupt */
    if (DMA_GetITStatus(DMA1_IT_TC1) == SET)
    {
        //CARD_ADC_Filter();
        printf("DMA_IRQ: ");
        gvu8AdcReady = 1;

        for(i=0; i<5; i++)
        {
            printf(" %4ld ", gvu16AdcValue[0]);
}
        printf (" ");

        /* Clear DMA1 Channel6 Half Transfer, Transfer Complete and Global interrupt pending bits */
        DMA_ClearITPendingBit(DMA1_IT_GL1);
    }
}

void ADC1_2_IRQHandler(void)
{
    u16 val;
    static u8 LockCnt = 0;  // 检测次数

    if (ADC_GetITStatus(ADC1, ADC_IT_EOC) == SET )
    {
        val = ADC_GetConversionValue(ADC1);
        printf("ADC_IRQ: %d ", val);
        /* Clear ADC1 AWD pending interrupt bit */
        ADC_ClearITPendingBit(ADC1, ADC_IT_EOC);
    }
}

#undef  ADC_IT_ENABLE
#undef  DMA_ENABLE

////////////////////////////////////////////////////////////////////////////////////

/*
* timer.c
*/
#include "sys.h"
#include "ADC.h"

// ADC 利用TIM2定时采集数据
void TIM2_Init(u16 u16Period, u16 u16Pulse, u16 u16Prescaler)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    TIM_OCInitTypeDef  TIM_OCInitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);        //使能定时器3时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB  | RCC_APB2Periph_AFIO, ENABLE);  //使能GPIO外设和AFIO复用功能模块时钟

    GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE); // 关闭JTAG 启用SW-DP
    GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2, ENABLE); //Timer2部分重映射  TIM3_CH2->B5

    //设置该引脚为复用输出功能,输出TIM2 CH2的PWM脉冲波形        GPIOB.3
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; // TIM2_CH2
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIO

    //初始化TIM2
    TIM_TimeBaseStructure.TIM_Period = u16Period; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值
    TIM_TimeBaseStructure.TIM_Prescaler = u16Prescaler; //设置用来作为TIMx时钟频率除数的预分频值
    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位

    TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE ); //使能指定的TIM2中断,允许更新中断

    //中断优先级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寄存器

    //初始化TIM2 Channel2 PWM模式
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //选择定时器模式:TIM脉冲宽度调制模式2
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //如果是PWM1要为Low,PWM2则为High
    TIM_OCInitStructure.TIM_Pulse = u16Pulse;
    TIM_OC2Init(TIM2, &TIM_OCInitStructure);  //根据T指定的参数初始化外设TIM3 OC2

    TIM_InternalClockConfig(TIM2);
    TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Enable);  //使能TIM3在CCR2上的预装载寄存器
    TIM_ARRPreloadConfig(TIM2, ENABLE);
    TIM_Cmd(TIM2, ENABLE);  //使能TIM3

}

void TIM2_IRQHandler(void)   //TIM2中断
{
    if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)  //检查TIM2更新中断发生与否
    {
        TIM_ClearITPendingBit(TIM2, TIM_IT_Update  );  //清除TIMx更新中断标志

        printf("TIM2!! ");
        gvu8AdcReady = 0;

    }
}

////////////////////////////////////////////////////////////////////////////////////



友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
3条回答
viphl@vip.qq.co
1楼-- · 2019-10-15 01:02
 精彩回答 2  元偷偷看……
15623052920
2楼-- · 2019-10-15 02:08
TGuest
3楼-- · 2019-10-15 03:14
帮顶。。

一周热门 更多>