这里会显示出您选择的修订版和当前版本之间的差别。
两侧同时换到之前的修订记录 前一修订版 后一修订版 | 前一修订版 | ||
icore3l_arm_10 [2020/11/25 11:20] zgf |
icore3l_arm_10 [2022/03/19 11:00] (当前版本) sean |
||
---|---|---|---|
行 2: | 行 2: | ||
|技术支持电话|**0379-69926675-801**||| | |技术支持电话|**0379-69926675-801**||| | ||
|技术支持邮件|Gingko@vip.163.com||| | |技术支持邮件|Gingko@vip.163.com||| | ||
- | |技术论坛|http://www.eeschool.org||| | ||
^ 版本 ^ 日期 ^ 作者 ^ 修改内容 ^ | ^ 版本 ^ 日期 ^ 作者 ^ 修改内容 ^ | ||
| V1.0 | 2020-11-25 | gingko | 初次建立 | | | V1.0 | 2020-11-25 | gingko | 初次建立 | | ||
行 50: | 行 49: | ||
{{ :icore3l:icore3l_cube_10_15.png?direct |}} | {{ :icore3l:icore3l_cube_10_15.png?direct |}} | ||
创建成功,打开工程。 | 创建成功,打开工程。 | ||
+ | \\ | ||
+ | \\ | ||
+ | \\ | ||
+ | \\ | ||
+ | ===== 实验十:ADC实验——电源监控 ===== | ||
+ | ==== 一、实验目的与意义 ==== | ||
+ | - 了解STM32 ADC结构 | ||
+ | - 了解STM32 ADC特征 | ||
+ | - 掌握ADC的使用方法 | ||
+ | - 掌握STM32 HAL库中ADC属性的配置方法 | ||
+ | - 掌握KEILMDK 集成开发环境使用方法 | ||
+ | ==== 二、实验设备及平台 ==== | ||
+ | - iCore3L 双核心板 | ||
+ | - 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.STM32F429 ADC介绍 === | ||
+ | * STM32F429内置有 3 个 12 位模数转换器 (ADC),每个 ADC 可共享多达 16 个外部通道,在单发或扫描模式下执行转换。在扫描模式下,将对一组选定的模拟输入执行自动转换 | ||
+ | ADC 接口内置的其它逻辑功能允许: | ||
+ | * **同步采样和保持** | ||
+ | * **交叉采样和保持** | ||
+ | * ADC 可以使用 DMA 控制器。利用模拟看门狗功能,可以非常精确地监视一路、多路或所有选定通道的转换电压。当转换电压超出编程的阈值时,将产生中断。 | ||
+ | * 为同步 A/D 转换和定时器,可由 TIM1、TIM2、TIM3、TIM4、TIM5、TIM8 定时器的任何一个触发 ADC。 | ||
+ | === 4.实验原理 === | ||
+ | STM32内部集成三个12位ADC,iCore3L的所有电源经过电阻分压或者直接接入STM32的ADC的输出通道内,输入电流经过高端电流检测芯片TP1001S3输入到ADC的输入通道内,从而实现电源监控功能。电压监控硬件连接示意图如下图所示: | ||
+ | {{ :icore3l:icore3l_arm_hal_10_1.png?direct |}} | ||
+ | 由上图可知: | ||
+ | * VCC=(1+R1/R2)*ADC_IN; | ||
+ | 故知: | ||
+ | * VCC=(1+49.9K/10K)*ADC_IN=6*ADC_IN; | ||
+ | 其它电源监控同理可得: | ||
+ | * D1V2=ADC_IN; | ||
+ | * D1V8=2*ADC_IN; | ||
+ | * D3V3=2*ADC_IN; | ||
+ | 电流监控硬件连接示意图如下图所示: | ||
+ | {{ :icore3l:icore3l_arm_hal_10_2.png?direct |}} | ||
+ | 由上图可知: | ||
+ | * ADC_IN=0.01*(VCC-LOAD)*R2; | ||
+ | 通过R1的电流: | ||
+ | * 100*ADC_IN/R2/R1; | ||
+ | 带入R2=10K,R1=0.02K: | ||
+ | * I=ADC_IN/2; | ||
+ | ==== 四、实验程序 ==== | ||
+ | 1.主函数 | ||
+ | <code c> | ||
+ | int main(void) | ||
+ | { | ||
+ | int i; | ||
+ | HAL_Init(); | ||
+ | SystemClock_Config(); | ||
+ | MX_GPIO_Init(); | ||
+ | MX_USART2_UART_Init(); | ||
+ | MX_ADC1_Init(); | ||
+ | MX_ADC3_Init(); | ||
+ | /* USER CODE BEGIN 2 */ | ||
+ | while (1) | ||
+ | { | ||
+ | if(systick._500ms_flag == 1) | ||
+ | { | ||
+ | LED_RED_ON; | ||
+ | systick._500ms_flag = 0; | ||
+ | for(i=0;i<5;i++) | ||
+ | { | ||
+ | my_adc.read(i); | ||
+ | } | ||
+ | usart1.initialize(115200); | ||
+ | usart1.printf("\x0c"); | ||
+ | usart1.printf("\033[1;32;40m"); | ||
+ | usart1.printf("Hello,I am iCore3L!\r\n\r\n"); | ||
+ | usart1.printf("[1.2V] %4.2fV,",my_adc.value[0]); //打印输入电源电压 | ||
+ | usart1.printf("[1.8V] %4.2fV,",my_adc.value[1]); | ||
+ | usart1.printf("[3.3V] %4.2fV,",my_adc.value[2]*2); | ||
+ | usart1.printf("[V] %4.2fV,",my_adc.value[3] * 6); | ||
+ | usart1.printf("[I] %3.0fmA\r\n",my_adc.value[4]/2*1000.); | ||
+ | LED_RED_OFF; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | </code> | ||
+ | 2.ADC初始化函数 | ||
+ | <code c> | ||
+ | void MX_ADC1_Init(void) | ||
+ | { | ||
+ | ADC_ChannelConfTypeDef sConfig = {0}; | ||
+ | hadc1.Instance = ADC1; | ||
+ | hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV8; | ||
+ | hadc1.Init.Resolution = ADC_RESOLUTION_12B; //ADC转换分辨率12位 | ||
+ | hadc1.Init.ScanConvMode = DISABLE; //非扫描模式 | ||
+ | hadc1.Init.ContinuousConvMode = DISABLE; //关闭连续转换 | ||
+ | hadc1.Init.DiscontinuousConvMode = DISABLE; //禁止不连续采样模式 | ||
+ | hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; //禁止触发检测 | ||
+ | hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START; //软件触发 | ||
+ | hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT; | ||
+ | hadc1.Init.NbrOfConversion = 1; | ||
+ | hadc1.Init.DMAContinuousRequests = DISABLE; | ||
+ | hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV; //关闭EOC中断 | ||
+ | if (HAL_ADC_Init(&hadc1) != HAL_OK) | ||
+ | { | ||
+ | Error_Handler(); | ||
+ | } | ||
+ | sConfig.Channel = ADC_CHANNEL_15; //通道15 | ||
+ | sConfig.Rank = 1; | ||
+ | sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES; //采样时间 | ||
+ | if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) | ||
+ | { | ||
+ | Error_Handler(); | ||
+ | } | ||
+ | } | ||
+ | void MX_ADC3_Init(void) | ||
+ | { | ||
+ | ADC_ChannelConfTypeDef sConfig = {0}; | ||
+ | hadc3.Instance = ADC3; | ||
+ | hadc3.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV8; | ||
+ | hadc3.Init.Resolution = ADC_RESOLUTION_12B; //ADC转换分辨率12位 | ||
+ | hadc3.Init.ScanConvMode = DISABLE; //非扫描模式 | ||
+ | hadc3.Init.ContinuousConvMode = DISABLE; //关闭连续转换 | ||
+ | hadc3.Init.DiscontinuousConvMode = DISABLE; //禁止不连续采样模式 | ||
+ | hadc3.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; //禁止触发检测 | ||
+ | hadc3.Init.ExternalTrigConv = ADC_SOFTWARE_START; //软件触发 | ||
+ | hadc3.Init.DataAlign = ADC_DATAALIGN_RIGHT; | ||
+ | hadc3.Init.NbrOfConversion = 1; | ||
+ | hadc3.Init.DMAContinuousRequests = DISABLE; | ||
+ | hadc3.Init.EOCSelection = ADC_EOC_SINGLE_CONV; //关闭EOC中断 | ||
+ | if(HAL_ADC_Init(&hadc3) != HAL_OK) | ||
+ | { | ||
+ | Error_Handler(); | ||
+ | } | ||
+ | sConfig.Channel = ADC_CHANNEL_6; //通道6 | ||
+ | sConfig.Rank = 1; | ||
+ | sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES; //采样时间 | ||
+ | if (HAL_ADC_ConfigChannel(&hadc3, &sConfig) != HAL_OK) | ||
+ | { | ||
+ | Error_Handler(); | ||
+ | } | ||
+ | } | ||
+ | </code> | ||
+ | 3.ADC读取函数 | ||
+ | <code c> | ||
+ | int read(int channel) | ||
+ | { | ||
+ | int i,k; | ||
+ | unsigned long int temp[20] = {0}; | ||
+ | unsigned short int data[100]; | ||
+ | ADC_ChannelConfTypeDef channel_config; | ||
+ | int channel_remap[5] = {ADC_CHANNEL_13,ADC_CHANNEL_6,ADC_CHANNEL_12,ADC_CHANNEL_7,ADC_CHANNEL_6}; | ||
+ | channel_config.Channel = channel_remap[channel]; | ||
+ | channel_config.Rank = 1; | ||
+ | channel_config.SamplingTime = ADC_SAMPLETIME_3CYCLES; | ||
+ | if(channel == 1 || channel == 3) | ||
+ | { | ||
+ | HAL_ADC_ConfigChannel(&hadc3,&channel_config); | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | HAL_ADC_ConfigChannel(&hadc1,&channel_config); | ||
+ | } | ||
+ | for(k = 0;k < 20;k ++) | ||
+ | { | ||
+ | for(i = 0;i < 100;i ++) | ||
+ | { | ||
+ | if(channel == 1 || channel == 3) | ||
+ | { | ||
+ | HAL_ADC_Start(&hadc3); | ||
+ | while(!__HAL_ADC_GET_FLAG(&hadc3,ADC_FLAG_EOC));//等待转换结束 | ||
+ | data[i] = HAL_ADC_GetValue(&hadc3); //将结果保存 | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | HAL_ADC_Start(&hadc1); | ||
+ | while(!__HAL_ADC_GET_FLAG(&hadc1,ADC_FLAG_EOC));//等待转换结束 | ||
+ | data[i] = HAL_ADC_GetValue(&hadc1); //将结果保存 | ||
+ | } | ||
+ | } | ||
+ | sort(data,100); | ||
+ | for(i = 40;i < 60;i++) | ||
+ | { | ||
+ | temp[k] += data[i]; | ||
+ | } | ||
+ | } | ||
+ | temp[k] = temp[k] / 20; | ||
+ | value = 0; | ||
+ | for(k = 0;k < 20;k ++) | ||
+ | { | ||
+ | value += temp[k]; | ||
+ | } | ||
+ | value /= 20; | ||
+ | my_adc.value[channel] = value * ADC_REF / 4096; | ||
+ | return value; | ||
+ | } | ||
+ | </code> | ||
+ | ==== 五、实验步骤 ==== | ||
+ | - 把仿真器与iCore3L的SWD调试口相连(直接相连或者通过转接器相连); | ||
+ | - 把iCore3L通过Micro USB线与计算机相连,为iCore3L供电; | ||
+ | - 打开Keil MDK 开发环境,并打开本实验工程; | ||
+ | - 烧写程序到iCore3L上; | ||
+ | - 也可以进入Debug 模式,单步运行或设置断点验证程序逻辑。 | ||
+ | ==== 六、实验现象 ==== | ||
+ | 串口一直向终端输出输入电源的数据。(关于PuTTY软件的使用,详情请看附录) | ||
+ | {{ :icore3l:icore3l_arm_hal_10_3.png?direct |}} | ||
+ | ===== 附录 ===== | ||
+ | 1.安装CH340驱动(双击安装,如果已安装忽略此步) | ||
+ | 2.iCore3L供电后,打开计算机——属性——设备管理器——端口 | ||
+ | {{ :icore3l:icore3l_arm_hal_10_4.png?direct |}} | ||
+ | 3.打开puTTY | ||
+ | {{ :icore3l:icore3l_arm_hal_10_5.png?direct |}} | ||
+ | 4.烧写程序进行验证 |