813|0

452

帖子

0

TA的资源

纯净的硅(初级)

楼主
 

【复旦微车规MCU FM33FT0A 系列】+定时ADC [复制链接]

本帖最后由 dirty 于 2024-1-25 14:16 编辑

        本篇讲述使用定时器与ADC,达到定时1s间隔读取ADC值。

一.关于外设了解

        开发板上有一颗可调电阻R57,接在MCU的PC11引脚,复用为ADC_IN6,使用12bit ADC功能。MCU有一个16位基本定时器(BSTIM16),作为定时用。

 

图1:ADC原理图接线

二.代码部分

1. 在mf_config.c添加ADC 与 定时器初始化函数,并将这些初始化放在MF_Config_Init以供调用。

(1).关于ADC初始化。有配置ADC引脚、通道选择、ADC位宽等

/**
  * [url=home.php?mod=space&uid=159083]@brief[/url]   ADC_Common Initialization function
  * @param  void
  * @retval None
  */
void MF_ADC_Common_Init(void)
{
    /*ADC CONFIG*/
    FL_ADC_CommonInitTypeDef    CommonInitStruct;

    CommonInitStruct.clockSource     = FL_CMU_ADC_CLK_SOURCE_RCHF;  /*配置ADC工作时钟源*/
    CommonInitStruct.clockPrescaler  = FL_ADC_CLK_PSC_DIV1;         /*配置ADC工作时钟分频*/
    CommonInitStruct.referenceSource = FL_ADC_REF_SOURCE_VDDA;      /*配置ADC参考源*/
    CommonInitStruct.bitWidth        = FL_ADC_BIT_WIDTH_12B;        /*配置ADC输出位宽*/
    (void)FL_ADC_CommonInit(&CommonInitStruct);
}

/**
  * @brief  ADC Initialization function
  * @param  void
  * @retval None
  */
void MF_ADC_Init(void)
{
    FL_GPIO_InitTypeDef    GPIO_InitStruct;

    FL_ADC_InitTypeDef    defaultInitStruct;

    GPIO_InitStruct.pin = FL_GPIO_PIN_11;                                       /*配置GPIO的引脚号*/
    GPIO_InitStruct.mode = FL_GPIO_MODE_ANALOG;                                 /*配置GPIO的功能模式*/
    GPIO_InitStruct.outputType = FL_GPIO_OUTPUT_PUSHPULL;                       /*配置GPIO的输出模式*/
    GPIO_InitStruct.pull = FL_GPIO_BOTH_DISABLE;                                /*配置GPIO上拉下拉模式*/
    GPIO_InitStruct.remapPin = FL_GPIO_PINREMAP_FUNCTON1;                       /*配置GPIO数字重定向功能*/
    GPIO_InitStruct.driveStrength = FL_GPIO_DRIVESTRENGTH_X3;                   /*配置GPIO驱动能力*/
    GPIO_InitStruct.analogSwitch = FL_DISABLE;                                  /*配置GPIO模拟开关功能*/
    (void)FL_GPIO_Init( GPIOC, &GPIO_InitStruct );                              /*GPIO初始化*/

    defaultInitStruct.conversionMode = FL_ADC_CONV_MODE_SINGLE;                 /*配置ADC转换模式*/
    defaultInitStruct.autoMode = FL_ADC_SINGLE_CONV_MODE_AUTO;                  /*配置ADC转换流程,仅对单次转换有效*/
    defaultInitStruct.waitMode = FL_DISABLE;                                    /*配置ADC等待模式:使用DMA搬运时必须禁止等待模式*/
    defaultInitStruct.overrunMode = FL_ENABLE;                                  /*配置ADC_Overrun模式*/
    defaultInitStruct.scanDirection = FL_ADC_SEQ_SCAN_DIR_FORWARD;              /*配置ADC扫描顺序*/
    defaultInitStruct.externalTrigConv = FL_ADC_TRIGGER_EDGE_NONE;              /*配置非软件触发使能及极性*/
    defaultInitStruct.triggerSource = FL_ADC_TRGI_LUT0;                         /*配置ADC非软件触发源*/
    defaultInitStruct.fastChannelTime = FL_ADC_FAST_CH_SAMPLING_TIME_4_ADCCLK;  /*配置ADC快速通道采样时间*/
    defaultInitStruct.lowChannelTime = FL_ADC_SLOW_CH_SAMPLING_TIME_192_ADCCLK; /*配置ADC慢速通道采样时间*/
    defaultInitStruct.oversamplingMode = FL_DISABLE;                            /*配置ADC过采样模式*/
    defaultInitStruct.overSampingMultiplier = FL_ADC_OVERSAMPLING_MUL_16X;      /*配置ADC过采样率*/
    defaultInitStruct.oversamplingShift = FL_ADC_OVERSAMPLING_SHIFT_4B;         /*配置ADC过采样结果移位*/

    (void)FL_ADC_Init(ADC,&defaultInitStruct );                                 /*ADC初始化*/

    FL_ADC_EnableSequencerChannel(ADC, FL_ADC_INTERNAL_AVREF);                  /*通道选择*/
    FL_ADC_EnableSequencerChannel(ADC, FL_ADC_EXTERNAL_CH6);


    FL_ADC_EnableDMAReq(ADC);                                                   /*配置ADC_DMA*/  
}
在MF_Config_Init里外设初始化
/**
  * @brief  The application entry point.
  * @retval int
  */

void MF_Config_Init(void)
{
    /*FUNCTION CALL*/

    //UART Printf
    MF_UART4_Init();
	
    //ADC Init
    #if(FUNCTION_ADC==1)
    MF_ADC_Common_Init();  /*ADC基础配置*/
    MF_ADC_Init();         /*ADC初始化配置*/
	  printf("adc init\r\n");
    #endif
	
    //Base Timer Init
    MF_BSTIM16_TimerBase_Init();
    MF_BSTIM16_Interrupt_Init();
    MF_NVIC_Init();

	printf("basetimer init\r\n");
	 
}

 

(2)关于基础定时器初始化。包含有定时器预分频、自动重装载值以及定时中断初始化

/**
  * @brief  BSTIM16_TimerBase Initialization function
  * @param  void
  * @retval None
  */
void MF_BSTIM16_TimerBase_Init(void)
{
    FL_BSTIM16_InitTypeDef    TimerBase_InitStruct;

    TimerBase_InitStruct.prescaler = 7999;
    TimerBase_InitStruct.autoReload = 999;
    TimerBase_InitStruct.autoReloadState = FL_ENABLE;
    TimerBase_InitStruct.clockSource = FL_CMU_BSTIM16_CLK_SOURCE_APBCLK;
    (void)FL_BSTIM16_Init(BSTIM16, &TimerBase_InitStruct);
}

/**
  * @brief  BSTIM16 Interrupt Initialization function
  * @param  void
  * @retval None
  */
void MF_BSTIM16_Interrupt_Init(void)
{
    FL_BSTIM16_ClearFlag_Update(BSTIM16);
    FL_BSTIM16_EnableIT_Update(BSTIM16);
}

/**
  * @brief  NVIC Initialization function
  * @param  void
  * @retval None
  */
void MF_NVIC_Init(void)
{
    FL_NVIC_ConfigTypeDef    InterruptConfigStruct;

    InterruptConfigStruct.preemptPriority = 0x02;
    FL_NVIC_Init(&InterruptConfigStruct, BSTIM_IRQn);
}

 

2.在adc.c添加,使用ADC DMA 采集数据,在DMA_IRQHandler中断里置位ADC完成标志。

static void ADC_DMA_Common_Init(void)
{
    FL_DMA_InitTypeDef DMA_InitStruct = {0};
    FL_NVIC_ConfigTypeDef    InterruptConfigStruct;

    DMA_InitStruct.periphAddress = FL_DMA_PERIPHERAL_FUNCTION1;                 /* 配置DMA通道功能 */
    DMA_InitStruct.direction = FL_DMA_DIR_PERIPHERAL_TO_RAM;                    /* 配置DMA通道方向 */
    DMA_InitStruct.memoryAddressIncMode = FL_DMA_MEMORY_INC_MODE_INCREASE;      /* 配置RAM的增减方向 */
    DMA_InitStruct.dataSize = FL_DMA_BANDWIDTH_16B;                             /* 配置DMA传输位宽 */
    DMA_InitStruct.priority = FL_DMA_PRIORITY_VERYHIGH;                         /* 配置DMA通道优先级:如应用于ADC通道,必须配置为最高 */
    DMA_InitStruct.circMode = FL_DISABLE;                                       /* 配置DMA通道循环缓存 */
    (void)FL_DMA_Init(DMA, &DMA_InitStruct, FL_DMA_CHANNEL_0);
    
    FL_DMA_Enable(DMA);                                                         /* 配置DMA全局开关 */


    FL_DMA_ClearFlag_TransferComplete(DMA,FL_DMA_CHANNEL_0);                    /* 清标志 */
    FL_DMA_EnableIT_TransferComplete(DMA,FL_DMA_CHANNEL_0);                     /* 配置DMA全程中断 */


    InterruptConfigStruct.preemptPriority = 2U;                                 /* 配置DMA的优先级 */
    FL_NVIC_Init(&InterruptConfigStruct,DMA_IRQn );
}


void ADC_DMA_Config(uint16_t *buffer, uint32_t length)
{
    FL_DMA_ConfigTypeDef DMA_ConfigStruct = {0};  
    DMA_ConfigStruct.memoryAddress = (uint32_t)buffer;                          /* 配置DMA_RAM地址 */
    DMA_ConfigStruct.transmissionCount = length - 1;                            /* 配置DMA传输长度 */
    (void)FL_DMA_StartTransmission(DMA, &DMA_ConfigStruct, FL_DMA_CHANNEL_0);
}


uint16_t DMAResult[ADC_VALUE_NUM];//2
void ADC_Config(void)
{
    FL_PMU_EnableAVREFBuffer(PMU);                                              /* 使能VREF BUFFER */

    ADC_DMA_Common_Init();                                                      /* DMA基础初始化配置 */
    ADC_DMA_Config(DMAResult, ADC_VALUE_NUM);//2                                               /* DMA初始化配置 */

    FL_ADC_ClearFlag_EndOfConversion(ADC);                                      /* 清标志 */
    FL_ADC_Enable(ADC);                                                         /* 启动ADC */
    FL_ADC_EnableSWConversion(ADC);                                             /* 开始转换 */
}

DMA中断置ADC完成标志位

volatile uint8_t ADCComplete = 0;
void DMA_IRQHandler(void)
{
    uint32_t IE_Flag,IF_Flag;
    IE_Flag = FL_DMA_IsEnabledIT_TransferComplete(DMA,FL_DMA_CHANNEL_0);        /* 获取中断使能以及中断标志状态 */
    IF_Flag = FL_DMA_IsActiveFlag_TransferComplete(DMA,FL_DMA_CHANNEL_0);
    if((0x01U == IE_Flag) && (0x01U == IF_Flag))
    {
        FL_DMA_ClearFlag_TransferComplete(DMA,FL_DMA_CHANNEL_0);                /* 清标志 */
        FL_ADC_ClearFlag_EndOfConversion(ADC);
        ADCComplete = 1;
    }

}

 

如下是计算ADC值

uint32_t GetSingleChannelVoltage_DMA(void)
{
    uint32_t GetChannelVoltage = 0;

    if (DMAResult[0] != 0)
    {
        GetChannelVoltage = (uint32_t)(((uint64_t)DMAResult[0] * ADC_VREF) / ((uint64_t)DMAResult[1] * 10));
    }

    return GetChannelVoltage;
}

 

3.在bstim16_timing.c添加启动定时器函数、定时器中断服务函数 并在中断置位定时器标志

volatile uint8_t time_flag = 0;

/**
  * @brief  使能BSTIM16
  * @param  void
  * @retval None
  */
void BSTIM16_Start(void)
{
    /* 使能BSTIM16 */
    FL_BSTIM16_Enable(BSTIM16);
}


/**
  * @brief  BSTIM中断服务函数
  * @param  void
  * @retval None
  */
void BSTIM_IRQHandler(void)
{
    uint32_t BSTIMUpdateIT = 0;
    uint32_t BSTIMUpdateFlag = 0;

    BSTIMUpdateIT = FL_BSTIM16_IsEnabledIT_Update(BSTIM16);
    BSTIMUpdateFlag = FL_BSTIM16_IsActiveFlag_Update(BSTIM16);
    
    if ((BSTIMUpdateIT == 0x01U) && (BSTIMUpdateFlag == 0x01U))
    {
        FL_BSTIM16_ClearFlag_Update(BSTIM16);
        time_flag=1;
        printf("process timer things...\r\n");
        /*
            处理更新事件...
        */
    }
}

 

4.在app_config.h配资头文件使能相关宏

#ifndef _APP_CONFIG_H_
#define _APP_CONFIG_H_


#ifdef  __cplusplus
extern "C"{
#endif


#include "main.h"
#include "fm33ft0xxa_fl.h"
#include "iwdt.h"
#include "svd.h"
#include "rmu.h"

#include "led.h"
#include "adc.h"
#include "atim.h"
#include "bstim16_timing.h"

#define FUNCTION_LED    0

#define FUNCTION_ADC    1
#define ADC_VALUE_NUM   2

#ifdef  __cplusplus
}
#endif

#endif

 

5.在main.c添加初始化及功能函数

int main(void)
{   
    /* 使能IWDT */
    IWDT_Init(FL_IWDT_PERIOD_4000MS);
    
    /* Initialize FL Driver Library */
    /* SHOULD BE KEPT!!! */
    FL_Init();
    
    /* 使能SVD, 阈值4.157V(falling)~4.257V(rising) */
    SVD_Init(SVD_MONTIOR_VDD, FL_SVD_WARNING_THRESHOLD_GROUP11, FL_SVD_REFERENCE_1P0V);
    /* 确认SVD监测结果是否高于阈值,如否则持续等待 */
    while(false == SVD_Result_Confirmed(SVD_HIGHER_THRESHOLD, 2000U/*us*/));
    
    /* 使能BOR */
    RMU_BOR_Init(FL_RMU_BOR_THRESHOLD_2P00V);
    
    MF_Config_Init();
    
    #if(FUNCTION_ADC==1)
    ADC_Config();
    #endif


    BSTIM16_Start();
	
    printf("All Peripher init finish\r\n");
   
    while(1)
    { 
        /* 清狗 */
        FL_IWDT_ReloadCounter(IWDT);
        
        /* 电源掉电监测处理 */
        PowerDownMonitoring();
    
        /* 功能执行 */    
        #if(FUNCTION_LED==1)

        LED_TOG_FUN(RED,   1, FL_DelayMs(200));
        LED_TOG_FUN(GREEN, 1, FL_DelayMs(200));
        LED_TOG_FUN(BULE,  1, FL_DelayMs(200));
        #endif
		
        #if(FUNCTION_ADC==1)
        if((0x01U == ADCComplete)&&(time_flag==1))
        {
            ADCComplete = 0;
			time_flag=0;
            GetVoltage = GetSingleChannelVoltage_DMA();  
            printf("Res_ADC:%d\r\n",GetVoltage);
			
            ADC_DMA_Config(DMAResult, ADC_VALUE_NUM);
            FL_ADC_ClearFlag_EndOfConversion(ADC);
            FL_ADC_Enable(ADC);
            FL_ADC_EnableSWConversion(ADC); 
        }
        #endif

    }
}

 

三.编译烧录及测试 

        全编译后,上电烧录,旋转可调电阻,查看日志。

图2:定时采集ADC 日志

 

        从日志可以看出定时器1s间隔,且调节电阻器,ADC值 发生变化。达到功能预期。

 

此帖出自汽车电子论坛
点赞 关注

回复
举报
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/10 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表