






扫描模式要等所有通道转换完成后才会产生eoc标志,每个通道转换完成会把转换值给数据寄存器,但是只有一个数据寄存器,所以我们要用到DMA对数据进行搬运

规则组类似于主流程,注入组类似中断,注入组打断规则组优先执行




信号源的输出阻抗对ADC的采样有影响表格为不同采样周期Ts(以ADC时钟周期计)对应的时间ts(以微秒计)和最大输入电阻RAIN max(以千欧计),如1.5个ADC采样周期的最大输入电阻为0.15kΩ,大于这个阻值采样的会值不准确



ADC单通道转换

我们用可调电阻PC2引脚(ADC0)
我们创建Vers_drv.c
#include <stdint.h>
#include <stdio.h>
#include "gd32f30x.h"
#include "delay.h"
static void GpioInit(void)
{
rcu_periph_clock_enable(RCU_GPIOC);
gpio_init(GPIOC,GPIO_MODE_AIN,GPIO_OSPEED_10MHZ,GPIO_PIN_2);
}
static void AdcInit(void)
{
/*使能时钟;*/
rcu_periph_clock_enable(RCU_ADC0);
/*设置分频系数;*/
rcu_adc_clock_config(RCU_CKADC_CKAHB_DIV6);//6分频 120Mhz / 6 = 20Mhz
/*设置独立模式:*/
adc_mode_config(ADC_MODE_FREE);
/*设置单次模式;*/
adc_special_function_config(ADC0,ADC_CONTINUOUS_MODE,ENABLE);//连续转换
/*设置数据对齐;*/
adc_data_alignment_config(ADC0,ADC_DATAALIGN_RIGHT);
/*设置转换通道个数;*/
adc_channel_length_config(ADC0,ADC_REGULAR_CHANNEL,1);
/*设置转换哪一个通道以及所处序列位置:*/
adc_regular_channel_config(ADC0 , 0, ADC_CHANNEL_12, ADC_SAMPLETIME_239POINT5);//PC2对应通道12,放在序列寄存器的0列中,239.5个周期
/*设置选择哪一个外部触发源;*/
adc_external_trigger_source_config(ADC0, ADC_REGULAR_CHANNEL, ADC0_1_2_EXTTRIG_REGULAR_NONE);//软件触发
/*使能外部触发;*/
adc_external_trigger_config(ADC0, ADC_REGULAR_CHANNEL,ENABLE);
/*使能ADC:*/
adc_enable(ADC0);
/*内部校准;*/
DelayNus(50);
adc_calibration_enable(ADC0);
adc_software_trigger_enable(ADC0, ADC_REGULAR_CHANNEL);//开启转换
}
/**
***********************************************************
* @brief ADC硬件初始化
* @param
* @return
***********************************************************
*/
void VresDvrInit(void)
{
GpioInit();
AdcInit();
}
/**
***********************************************************
* @brief ADC读取函数
* @param
* @return adc值
***********************************************************
*/
uint16_t GetAdcVal(void)
{
// while(!adc_flag_get(ADC0, ADC_FLAG_EOC));//等待转换完成
return adc_regular_data_read(ADC0);
}
/**
***********************************************************
* @brief ADC测试函数
* @param
* @return
***********************************************************
*/
void VresDrvTest()
{
uint16_t AdcVal = GetAdcVal();
float Voltage = (float)AdcVal / 4095 * 3.3f;//转换成电压值
printf("AdcVal = %d, Voltage = %.1f\n",AdcVal,Voltage);
DelayNms(1000);
}
.h
#ifndef _VRES_DRV_H_
#define _VRES_DRV_H_
/**
***********************************************************
* @brief ADC测试函数
* @param
* @return
***********************************************************
*/
void VresDrvTest();
/**
***********************************************************
* @brief ADC读取函数
* @param
* @return adc值
***********************************************************
*/
uint16_t GetAdcVal(void);
/**
***********************************************************
* @brief ADC硬件初始化
* @param
* @return
***********************************************************
*/
void VresDvrInit(void);
#endif
main
#include <stdint.h>
#include <stdio.h>
#include "led_drv.h"
#include "key_drv.h"
#include "systick.h"
#include "usart_drv.h"
#include "delay.h"
#include "usb2com_app.h"
#include "hmi_app.h"
#include "rtc_drv.h"
#include "vres_drv.h"
typedef struct
{
uint8_t run; // 调度标志,1:调度,0:挂起
uint16_t timCount; // 时间片计数值
uint16_t timRload; // 时间片重载值
void (*pTaskFuncCb)(void); // 函数指针变量,用来保存业务功能模块函数地址
} TaskComps_t;/*任务调度结构体*/
static TaskComps_t g_taskComps[] = /*任务调度结构体数组,存放各个业务功能模块调度参数*/
{/*填入各个业务功能模块*/
{0, 1000, 1000, HmiTask},
{0, 200, 200, usartTask},
/* 添加业务功能模块 */
};
#define TASK_NUM_MAX (sizeof(g_taskComps) / sizeof(g_taskComps[0]))
/*用宏定义计算结构体数组的个数*///sizeof(g_taskComps):计算整个数组 g_taskComps 的大小(以字节为单位)。
//sizeof(g_taskComps[0]):计算数组中单个元素的大小(以字节为单位)。
//通过整个数组的大小除以单个元素的大小,得到数组中元素的数量
/*
******************************************
* @brief 任务调度函数(判断所有业务模块的标志位)
* @param
* @return
********************************************
*/
static void TaskHandler(void)
{
for (uint8_t i = 0; i < TASK_NUM_MAX; i++)
{
if (g_taskComps[i].run) // 判断时间片标志
{
g_taskComps[i].run = 0; // 标志清零
g_taskComps[i].pTaskFuncCb(); // 执行调度业务功能模块
}
}
}
/*
******************************************
* @brief 时间片递减函数 1ms-1时间片
* @param
* @return
********************************************
*/
static void TaskScheduleCb(void)
{
for (uint8_t i = 0; i < TASK_NUM_MAX; i++)
{
if (g_taskComps[i].timCount)
{
g_taskComps[i].timCount--;
if (g_taskComps[i].timCount == 0)
{
g_taskComps[i].run = 1;
g_taskComps[i].timCount = g_taskComps[i].timRload;
}
}
}
}
static void DrvInit(void)
{
SystickInit();
LedDrvInit();
KeyDrvInit();
DelayInit();
UsartDrv_Init();
RtcDrvInit();
VresDvrInit();
}
static void AppInit(void)
{
Usb2ComAppInit();
TaskScheduleCbReg(TaskScheduleCb);
}
#include <time.h>
int main(void)
{
DrvInit();
AppInit();
RtcTime_t rtcTime = {2025 , 9, 1, 19, 18, 0};
SetRtcTime(&rtcTime);
while (1)
{
//TaskHandler();
VresDrvTest();
}
}
多通道转换(DMA)
vres_drv.c
#include <stdint.h>
#include <stdio.h>
#include "gd32f30x.h"
#include "delay.h"
/**
***********************************************************
* @brief ADC GPIO初始化
* @param
* @return
***********************************************************
*/
static void GpioInit(void)
{
rcu_periph_clock_enable(RCU_GPIOC);
gpio_init(GPIOC,GPIO_MODE_AIN,GPIO_OSPEED_10MHZ,GPIO_PIN_2);
gpio_init(GPIOC,GPIO_MODE_AIN,GPIO_OSPEED_10MHZ,GPIO_PIN_3);
}
/**
***********************************************************
* @brief ADC初始化
* @param
* @return
***********************************************************
*/
static void AdcInit(void)
{
/* 使能时钟;*/
rcu_periph_clock_enable(RCU_ADC0);
/* 设置分频系数;*/
rcu_adc_clock_config(RCU_CKADC_CKAPB2_DIV6); // 6分频,120MHz / 6 = 20MHz
/* 设置独立模式;*/
adc_mode_config(ADC_MODE_FREE);
/* 设置连续模式;*/
adc_special_function_config(ADC0, ADC_CONTINUOUS_MODE, ENABLE);
/* 设置扫描模式;*/
adc_special_function_config(ADC0, ADC_SCAN_MODE, ENABLE);
/* 设置数据对齐;*/
adc_data_alignment_config(ADC0, ADC_DATAALIGN_RIGHT);
/* 设置转换通道个数;*/
adc_channel_length_config(ADC0, ADC_REGULAR_CHANNEL, 2);
/* 设置转换哪一个通道以及所处序列位置;*/
adc_regular_channel_config(ADC0, 0, ADC_CHANNEL_12, ADC_SAMPLETIME_239POINT5); // PC2对应通道12,放在序列寄存器的0序列中,239.5个周期
adc_regular_channel_config(ADC0, 1, ADC_CHANNEL_13, ADC_SAMPLETIME_239POINT5); // PC2对应通道12,放在序列寄存器的0序列中,239.5个周期
/* 设置选择哪一个外部触发源;*/
adc_external_trigger_source_config(ADC0, ADC_REGULAR_CHANNEL, ADC0_1_2_EXTTRIG_REGULAR_NONE);
/* 使能外部触发;*/
adc_external_trigger_config(ADC0, ADC_REGULAR_CHANNEL, ENABLE);
/* 使能ADC的DMA功能;*/
adc_dma_mode_enable(ADC0);
/* 使能ADC;*/
adc_enable(ADC0);
/* 内部校准;*/
DelayNus(50);
adc_calibration_enable(ADC0);
adc_software_trigger_enable(ADC0, ADC_REGULAR_CHANNEL);
}
/**
***********************************************************
* @brief ADC DMA初始化函数
* @param
* @return
***********************************************************
*/
#define ADC0_RDATA_ADDR (ADC0 + 0x4C)
static uint16_t g_adcVal[2];
static void DmaInit(void)
{
/*使能DMA时钟*/
rcu_periph_clock_enable(RCU_DMA0);
/*复位DMA通道;*/
dma_deinit(DMA0,DMA_CH0);
dma_parameter_struct dmaStruct;//创建dma结构体变量(自带)
dma_struct_para_init(&dmaStruct);
/*配置传输方向;*/
dmaStruct.direction = DMA_PERIPHERAL_TO_MEMORY;//片上外设到存储器内存
/*配置数据源地址;*/
dmaStruct.periph_addr = ADC0_RDATA_ADDR;//adc数据寄存器地址
/*配置源地址是固定的还是增长的;*/
dmaStruct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;//源地址固定
/*配置源数据传输位宽;*/
dmaStruct.periph_width = DMA_PERIPHERAL_WIDTH_16BIT;//16位数据
/*配置数据目的地址;*///(uint32_t)g_rcvDataBuf表示是将数组的地址值转换为一个 uint32_t 类型的整数
dmaStruct.memory_addr = (uint32_t)g_adcVal;
/*配置目的地址是固定的还是增长的;*/
dmaStruct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;//目的地址自增
/*配置目的数据传输位宽;*/
dmaStruct.memory_width = DMA_MEMORY_WIDTH_16BIT;
/*配置数据传输最大次数;*/
dmaStruct.number = 2;
/*配置DMA通道优先级;*/
dmaStruct.priority = DMA_PRIORITY_HIGH;//优先级高
/*DMA初始化*/
dma_init(DMA0, DMA_CH0, &dmaStruct);
/*使能DMA循环模式搬运数据A*/
dma_circulation_enable(DMA0, DMA_CH0);
/*使能DMA通道;*/
dma_channel_enable(DMA0,DMA_CH0);
}
/**
***********************************************************
* @brief ADC硬件初始化
* @param
* @return
***********************************************************
*/
void VresDvrInit(void)
{
GpioInit();
AdcInit();
DmaInit();
}
/**
***********************************************************
* @brief ADC测试函数
* @param
* @return
***********************************************************
*/
void VresDrvTest()
{
float CH1 = (float)g_adcVal[0] / 4095 * 3.3f;//转换成电压值
float CH2 = (float)g_adcVal[1] / 4095 * 3.3f;//转换成电压值
printf("CH1 = %.1f, CH2 = %.1f\n",CH1,CH2);
DelayNms(1000);
}
vres_drv.h
#ifndef _VRES_DRV_H_
#define _VRES_DRV_H_
/**
***********************************************************
* @brief ADC测试函数
* @param
* @return
***********************************************************
*/
void VresDrvTest();
/**
***********************************************************
* @brief ADC硬件初始化
* @param
* @return
***********************************************************
*/
void VresDvrInit(void);
#endif

最低0.47元/天 解锁文章
1万+

被折叠的 条评论
为什么被折叠?



