|  **银杏科技有限公司旗下技术文档发布平台**  ||||
|技术支持电话|**0379-69926675-801**|||
|技术支持邮件|Gingko@vip.163.com|||
^  版本  ^  日期  ^  作者  ^  修改内容  ^
|  V1.0  |  2020-07-28  |  gingko  |  初次建立  | 
===== STM32CubeMX教程十一——独立ADC实验 =====
1.在主界面选择File-->New Project   或者直接点击ACCEE TO MCU SELECTOR  
{{ :icore4t:icore4t_cube_11_1.png?direct |}}
2.出现芯片型号选择,搜索自己芯片的型号,双击型号,或者点击Start Project进入配置
在搜索栏的下面,提供的各  种查找方式,可以选择芯片内核,型号,等等,可以帮助你查找芯片。本实验选取的芯片型号为:STM32H750IBKx。
{{ :icore4t:icore4t_cube_11_2.png?direct |}}
3.配置RCC,使用外部时钟源
{{ :icore4t:icore4t_cube_11_3.png?direct |}}
4.时基源选择SysTick
{{ :icore4t:icore4t_cube_11_4.png?direct |}}
5.将PA10设置为GPIO_Output
{{ :icore4t:icore4t_cube_11_5.png?direct |}}
6.引脚模式配置
{{ :icore4t:icore4t_cube_11_6.png?direct |}}
7.设置串口
{{ :icore4t:icore4t_cube_11_7.png?direct |}}
8.在NVIC Settings一栏使能接收中断
{{ :icore4t:icore4t_cube_11_8.png?direct |}}
9.配置ADC
{{ :icore4t:icore4t_cube_11_9.png?direct |}}
10.时钟源设置,选择外部高速时钟源,配置为最大主频
{{ :icore4t:icore4t_cube_11_10.png?direct |}}
{{ :icore4t:icore4t_cube_11_11.png?direct |}}
11.工程文件的设置, 这里就是工程的各种配置 我们只用到有限几个,其他的默认即可  IDE我们使用的是 MDK V5.27
{{ :icore4t:icore4t_cube_11_12.png?direct |}}
12.点击Code Generator,进行进一步配置
{{ :icore4t:icore4t_cube_11_13.png?direct |}}
  * **Copy all used libraries into the project folder**
  * **将HAL库的所有.C和.H都复制到所建工程中**
    * 优点:这样如果后续需要新增其他外设又可能不再用STM32CubeMX的时候便会很方便
    * 缺点:体积大,编译时间很长
  * **Copy only the necessary library files**
  * **只复制所需要的.C和.H(推荐)**
    * 优点:体积相对小,编译时间短,并且工程可复制拷贝
    * 缺点:新增外设时需要重新用STM32CubeMX导入
  * **Add necessary library files as reference in the toolchain project configuration file**
  * **不复制文件,直接从软件包存放位置导入.C和.H**
    * 优点:体积小,比较节约硬盘空间
    * 缺点:复制到其他电脑上或者软件包位置改变,就需要修改相对应的路径
自行选择方式即可
13.然后点击GENERATE CODE  创建工程
{{ :icore4t:icore4t_cube_11_14.png?direct |}}
创建成功,打开工程。
\\
\\
===== 实验十一:独立ADC实验——输入电源监控 =====
==== 一、 实验目的与意义 ====
  - 了解STM32 ADC结构
  - 了解STM32 ADC特征
  - 掌握ADC的使用方法
  - 掌握STM32 HAL库中ADC属性的配置方法
  - 掌握KEILMDK 集成开发环境使用方法
==== 二、 实验设备及平台 ====
  - iCore4TX 双核心板[[https://item.taobao.com/item.htm?spm=a1z10.1-c-s.w4004-22598974120.3.29da532fLkazHH&id=614919247574|点击购买]]。
  - JLINK(或相同功能)仿真器
  - Micro USB线缆
  - Keil MDK 开发平台
  - STM32CubeMX开发平台
  - 装有WIN XP(及更高版本)系统的计算机
==== 三、 实验原理 ====
=== 1.ADC介绍 ===
  * ADC是A/D转换部件,单片机不能直接处理模拟量,所以需要ADC将模拟量转换为数字量后,在进行处理。在使用单片机进行模拟数据处理的过程中,ADC至关重要。ADC以下几种类型:
  * **积分型**:积分型AD工作原理是将输入电压转换成时间(脉冲宽度信号)或频率(脉冲频率),然后由定时器/计数器获得数字值。其优点是用简单电路就能获得高分辨率,抗干扰能力强,但缺点是由于转换精度依赖于积分时间,因此转换速率极低。初期的单片AD转换器大多采用积分型,现在逐次比较型已逐步成为主流。
  * **逐次比较型:**逐次比较型AD由一个比较器和DA转换器通过逐次比较逻辑构成,从MSB开始,顺序地对每一位将输入电压与内置DA转换器输出进行比较,经n次比较而输出数字值。其电路规模属于中等。其优点是速度较高、功耗低,在低分辨率(<12位)时价格便宜,但高精度(>12位)时价格很高。
  * **并行比较型/串并行比较型:**并行比较型AD采用多个比较器,仅作一次比较而实行转换,又称FLash(快速)型。由于转换速率极高,n位的转换需要2n-1个比较器,因此电路规模也极大,价格也高,只适用于视频AD转换器等速度特别高的领域。串并行比较型AD结构上介于并行型和逐次比较型之间,最典型的是由2个n/2位的并行型AD转换器配合DA转换器组成,用两次比较实行转换,所以称为 Half flash(半快速)型。还有分成三步或多步实现AD转换的叫做分级(Multistep/Subrangling)型AD,而从转换时序角度又可称为流水线(Pipelined)型AD,现代的分级型AD中还加入了对多次转换结果作数字运算而修正特性等功能。这类AD速度比逐次比较型高,电路 规模比并行型小。
  * **Σ-Δ(Sigma delta)调制型:**Σ-Δ型AD由积分器、比较器、1位DA转换器和数字滤波器等组成。原理上近似于积分型,将输入电压转换成时间(脉冲宽度)信号,用数字滤波器处理后得到数字值。电路的数字部分基本上容易单片化,因此容易做到高分辨率。主要用于音频和测量。
  * **电容阵列逐次比较型:**电容阵列逐次比较型AD在内置DA转换器中采用电容矩阵方式,也可称为电荷再分配型。一般的电阻阵列DA转换器中多数电阻的值必须一致,在单芯片上生成高 精度的电阻并不容易。如果用电容阵列取代电阻阵列,可以用低廉成本制成高精度单片AD转换器。最近的逐次比较型AD转换器大多为电容阵列式的。
  * **压频变换型:**压频变换型(Voltage-Frequency Converter)是通过间接转换方式实现模数转换的。其原理是首先将输入的模拟信号转换成频率,然 后用计数器将频率转换成数字量。从理论上讲这种AD的分辨率几乎可以无限增加,只要采样的时间能够满足输出频率分辨率要求的累积脉冲个数的宽度。其优点是分辨率高、功耗低、价格低,但是需要外部计数电路共同完成AD转换。
=== 2.ADC主要参数介绍 ===
  * **ADC主要参数有以下几点:**
  * **分辨率**:数字量变化一个最小量时模拟量的变化量,定义为满刻度与2n的比值。分辨率又称精度,通常以数字信号的位数来表示。
  * **转换速率**:完成一次A/D转换所需要时间的倒数,值越大表示转换得越快。积分型AD的转换时间是毫秒级属低速AD,逐次比 较型AD是微秒级属中速AD,全并行/串并行型AD可达到纳秒级。
  * **量化误差**:由于AD的有限分辨率而引起的误差,即有限分辨率AD的阶梯状转移特性曲线与无限分辨率AD(理想AD)的转移特 性曲线(直线)之间的最大偏差。通常是1 个或半个最小数字量的模拟变化量,表示为1LSB、1/2LSB。
  * **偏移误差**:输入信号为零时输出信号不为零的值,可外接电位器调至最小。
  * **满刻度误差**:满度输出时对应的输入信号与理想输入信号值之差。
  * **线性度**:实际转换器的转移函数与理想直线的最大偏移。
=== 3.STM32H750 ADC介绍 ===
  * STM32H750xx系列有3个ADC,都可以独立工作,其中ADC1和ADC2还可以组成双重模式(提高采样率)。STM32H750的ADC分辨率高达16位,每个ADC具有多达20个的采集通道,这些通道的A/D转换可以单次、连续、扫描或间断模式执行。ADC的结果可以左对齐或右对齐方式存储在32位数据寄存器中。
  * 原理图:
{{ :icore4t:icore4t_arm_hal_11_1.png?direct |}} 
==== 四、 实验程序 ====
=== 1. 主函数 ===
int main(void)
{
  HAL_Init();
  SystemClock_Config();
  i2c.initialize();
  axp152.initialize();
  axp152.set_dcdc1(3500);//[ARM & FPGA]
  axp152.set_dcdc2(1200);//[FPGA INT]
  axp152.set_dcdc3(3300);//[DCOUT3]
  axp152.set_dcdc4(3300);//[DCOUT4]
  axp152.set_aldo1(3300);//[BK3]
  axp152.set_aldo2(3300);//[ALDOOUT2]
  axp152.set_dldo1(3300);//[BK0]
  axp152.set_dldo2(3300);//[BK1]
  HAL_Delay(200);
  
  MX_GPIO_Init();
  MX_USART2_UART_Init();
  MX_ADC1_Init();
  /* USER CODE BEGIN 2 */
    usart2.initialize(115200);
  while (1)
  {
        if(systick._500ms_flag == 1){
            systick._500ms_flag = 0;
            LED_ON;
            my_adc.read(0);
            usart2.printf("\x0c");
            usart2.printf("\033[1;32;40m");
            usart2.printf("Hello,I am iCore4TX!\r\n\r\n");       
            usart2.printf("[V    ] %4.2fV\r\n",my_adc.value[0] * 6); 
 //打印输入电源电压值
            LED_OFF;        
        }
  }
=== 2. ADC初始化函数 ===
void MX_ADC1_Init(void)
{
  ADC_MultiModeTypeDef multimode = {0};
  ADC_ChannelConfTypeDef sConfig = {0};
  hadc1.Instance = ADC1;
  hadc1.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV16;
  hadc1.Init.Resolution = ADC_RESOLUTION_16B;  //ADC转换分辨率16位
  hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;  //非扫描模式
  hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;  //关闭 EOC 中断
  hadc1.Init.LowPowerAutoWait = DISABLE;  //自动低功耗关闭
  hadc1.Init.ContinuousConvMode = DISABLE;  //关闭连续转换
  hadc1.Init.NbrOfConversion = 1;
  hadc1.Init.DiscontinuousConvMode = DISABLE;  //禁止不连续采样模式
  hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;  //软件触发
  hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;  //禁止触发检测
  hadc1.Init.ConversionDataManagement = ADC_CONVERSIONDATA_DR;
  hadc1.Init.Overrun = ADC_OVR_DATA_PRESERVED;  //过采样关闭
  hadc1.Init.LeftBitShift = ADC_LEFTBITSHIFT_NONE;
  hadc1.Init.OversamplingMode = DISABLE;
  if (HAL_ADC_Init(&hadc1) != HAL_OK)
  {
    Error_Handler();
  }
  multimode.Mode = ADC_MODE_INDEPENDENT;
  if (HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode) != HAL_OK)
  {
    Error_Handler();
  }
  sConfig.Channel = ADC_CHANNEL_16;  //通道16
  sConfig.Rank = ADC_REGULAR_RANK_1;  //第 1 个序列
  sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;  //采样时间
  sConfig.SingleDiff = ADC_SINGLE_ENDED;
  sConfig.OffsetNumber = ADC_OFFSET_NONE;
  sConfig.Offset = 0;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
}
=== 3. ADC读取函数 ===
int read(int channel)
{
    int i;
    unsigned long int temp = 0;
    unsigned short int data[50];
    ADC_ChannelConfTypeDef channel_config;
    int channel_remap[2] = {ADC_CHANNEL_16,ADC_CHANNEL_1};
    
    channel_config.Channel = channel_remap[channel];
    channel_config.Offset = 0;
    channel_config.Rank = ADC_REGULAR_RANK_1;
    channel_config.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
    channel_config.SingleDiff = ADC_SINGLE_ENDED;
    channel_config.OffsetNumber = ADC_OFFSET_NONE;    
    
    for(i = 0;i < 50;i ++){
        if(channel == 0){
            HAL_ADC_ConfigChannel(&hadc1,&channel_config);
            HAL_ADC_Start(&hadc1);
            while(!__HAL_ADC_GET_FLAG(&hadc1,ADC_FLAG_EOC));
            data[i] = HAL_ADC_GetValue(&hadc1);
        }
    }
    sort(data,50);
    for(i = 20;i < 30;i++){
        temp += data[i];
    }
    temp = temp / 10;
    if(channel == 0){
        my_adc.value[channel] = temp * ADC_REF / 65536;
    }
    
    return temp;
}
==== 五、 实验步骤 ====
  - 把仿真器与iCore4TX的SWD调试口相连(直接相连或者通过转接器相连);
  - 把iCore4TX通过Micro USB线与计算机相连,为iCore4TX供电;
  - 打开Keil MDK 开发环境,并打开本实验工程;
  - 烧写程序到iCore4TX上;
  - 也可以进入Debug 模式,单步运行或设置断点验证程序逻辑。
==== 六、 实验现象 ====
{{ :icore4tx:icore4tx_arm_hal_11_2.png?direct |}} 
串口一直向终端输出输入电源的数据。