# P010_ICDEXP **Repository Path**: LPBStudio/P010_ICDEXP ## Basic Information - **Project Name**: P010_ICDEXP - **Description**: No description available - **Primary Language**: C++ - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2025-04-12 - **Last Updated**: 2025-04-16 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # P010_ICDEXP #### 介绍 #### 软件架构 软件架构说明 #### 安装教程 1. xxxx 2. xxxx 3. xxxx #### 使用说明 1. xxxx 2. xxxx 3. xxxx #### 参与贡献 1. Fork 本仓库 2. 新建 Feat_xxx 分支 3. 提交代码 4. 新建 Pull Request #### 特技 Time设置: TIM1是挂在APB2总线; 预分频系数设置为36000-1,自动重载值为1000-1 // 启动定时器 HAL_TIM_Base_Start_IT(&htim1); // 定时器中断函数 void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { } 1、在 Parameter Settings 页配置预分频系数为 31,计数周期(自动加载值)为 999,定时器溢出频率,即PWM的周期,就是 F_PWM=64MHz/(31+1)/(999+1) = 2kHz PWM频率: Fpwm =Tclk / ((arr+1)*(psc+1))(单位:Hz) arr 是计数器值;Prescaler(PSC - 16 bits Value) psc 是预分频值;Couner Period(AutoReload Register - 16 bits value) 占空比: Duty circle = TIM3->CCR1 / arr(单位:%) TIMx->CCRx 用户设定值(PWM Generation Channel x -- Pulse(16 bits value)); 比如 定时器频率Tclk = 64Mhz arr=999 psc=31 那么PWM频率就是2KHz arr=999,TIM3->CCR1=250 则pwm的占空比为25% 改CCR1可以修改占空比,修改arr可以修改频率 2、程序代码 // 启动PWM HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_1); // 设置占空比,函数可能因为版本不同,有大小写区分,在实际编程时需要注意 __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, pwmVal); //修改比较值,修改占空比 // 或者直接修改寄存器,以修改占空比 htim3.Instance->CCR1 = pwmVal; ADC设置: 1、 ADCs_Common_Settings: Mode: Independent mod 独立 ADC 模式,当使用一个 ADC 时是独立模式,使用两个 ADC 时是双模式,在双模式下还有很多细分模式可选,具体配置 ADC_CR1:DUALMOD 位。 ADC_Settings: Data Alignment: Right alignment 转换结果数据右对齐,一般我们选择右对齐模式。 Left alignment 转换结果数据左对齐。 Scan Conversion Mode: Disabled 禁止扫描模式。如果是单通道 AD 转换使用 DISABLE。 Enabled 开启扫描模式。如果是多通道 AD 转换使用 ENABLE。 Continuous Conversion Mode: Disabled 单次转换。转换一次后停止需要手动控制才重新启动转换。 Enabled 自动连续转换。 DiscontinuousConvMode: Disabled 禁止间断模式。这个在需要考虑功耗问题的产品中很有必要,也就是在某个事件触发下,开启转换。 Enabled 开启间断模式。 ADC_Regular_ConversionMode: Enable Regular Conversions 是否使能规则转换。 Number Of Conversion ADC转换通道数目,有几个写几个就行。 External Trigger Conversion Source 外部触发选择。这个有多个选择,一般采用软件触发方式。 Rank: Channel ADC转换通道 Sampling Time 采样周期选择,采样周期越短,ADC 转换数据输出周期就越短但数据精度也越低,采样周期越长,ADC 转换数据输出周期就越长同时数据精度越高。 ADC_Injected_ConversionMode: Enable Injected Conversions 是否使能注入转换。注入通道只有在规则通道存在时才会出现。 WatchDog: Enable Analog WatchDog Mode 是否使能模拟看门狗中断。当被 ADC 转换的模拟电压低于低阈值或者高于高阈值时,就会产生中断。 2、ADC时钟配置;ADC 的转换时间跟 ADC 的输入时钟和采样时间有关。 公式为:Tconv = 采样时间 + 12.5 个周期。当 ADCLK = 14MHZ (最高),采样时间设置为 1.5 周期(最快), 那么总的转换时间(最短)Tconv = 1.5 周期 + 12.5 周期 = 14 周期 = 1us。 一般我们设置 PCLK2=64M,经过 ADC 预分频器能分频到最大的时钟只能是 8M, 采样周期设置为 1.5 个周期,算出最短的转换时间为 1.75us,这个才是最常用的; 4、ADC的多通道连续数据采集,只能使用DMA(Direct Memory Access,直接内存存取)方式进行; 4.1、在DMA Setting中启动ADC的DMA; 4.2、在main中,初始化时,需要将MX_DMA_Init()函数放置到MX_ADC1_Init()函数之前执行,否则,可能导致结果不正确; 4.3、代码: // 使用DMA启动方式,必须先定义一个用于接收结果的数组;N为数组数量,根据具体通道数量决定 // volatile 可以删除 volatile uint32_t ADC_Value[T*N]; // 启动ADC // 在while(1)前面以DMA方式开启ADC装换。HAL_ADC_Start_DMA()函数第二个参数为数据存储起始地址,第三个参数为DMA传输数据的长度。 HAL_ADC_Start_DMA(&hadc1,(uint32_t*)&ADC_Value,sizeof(ADC_Value)); // 此方式错误 HAL_ADC_Start_DMA(&hadc1,(uint32_t*)&ADC_Value,T*N); // 第三个参数为通道数量,注意:DMA缓冲区数据宽度与设置相同 // 由于DMA采用了连续传输的模式,ADC采集到的数据会不断传到到存储器中(此处即为数组ADC_Value)。ADC采集的数据从ADC_Value[0]一直存储到ADC_Value[99],然后采集到的数据又重新存储到ADC_Value[0],一直到ADC_Value[99]。所以ADC_Value数组里面的数据会不断被刷新。这个过程中是通过DMA控制的,不需要CPU参与。我们只需读取ADC_Value里面的数据即可得到ADC采集到的数据。 // ADC中断函数,仅使用DMA时依然也会调用 void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* AdcHandle) { } 4.4、DMA数据读取; DMA可以数据缓冲区可以定义为通道数整数倍的大小,转换成功后会依次放入缓冲区,因此可以直接一次接受多个数据,从而计算平均值 DMA设置中,必须将Data Width设置为word,同时Mode设置为Circular; 同时必须在NVIC项目下,将Force DMA channels Interrupts的选项取消,否则将造成其他中断无法执行; 在main中,初始化时,必须将MX_DMA_Init()函数放置到MX_ADC1_Init()函数之前执行,否则,将会导致没有结果结果不正确; 4.5、使用STM32内部的Vrefint后,计算VADC的公式: Vrefint=1200mV; ADC1.7:ADC转换结果 Vadc=(Vrefint * 0xFFF) / ADC1.7 4.6、VREFINT_CAL的使用 VDDA = 3.0V x VREFINT_CAL / VREFINT_DATA 这个公式是咋么来的的呢?下面我们以上 STM32L476 这个图为例来推导一下。 ST 通过配置将 VREFINT 连接到 ADC 后,则有: VREFINT = 3.3V * (VREFINT_CAL / 4095); VREFINT_CAL 就是校准条件下的 ADC 采样值 我们自己通过配置将 VREFINT 连接到 ADC:VREFINT = VDDA * (VREFINT_DATA / 4095); 因此,VDDA * (VREFINT_DATA / 4095) = 3.3 * (VREFINT_CAL / 4095); VDDA = 3.3V x VREFINT_CAL / VREFINT_DATA VREFINT_CAL = *(__IO uint16_t *)(0X1FFFF7BA); VDDA_VAL = (3.3*VREFINT_CAL)/VREFINT_DATA; 3、代码 // 单次转换代码 HAL_ADCEx_Calibration_Start(&hadc1); //AD校准 HAL_ADC_Start_IT(&hadc1); //开启ADC中断转换 // ADC中断函数 void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) { ADC_ConvertedValue = HAL_ADC_GetValue(hadc); } 特技 Git无法提交问题: (1)先把git的东西fetch到你本地然后merge后再push $ git fetch origin master $ git merge origin FETCH_HEAD 先抓取远程仓库的更新到本地,然后与你的本地仓库合并,(如果有冲突就要解决冲突后再合并,冲突问题比较复杂,这里就不详细说了),这样就可以使远程仓库和你本地仓库一致了,然后就可以提交修改了。 (1补充说明)这2句命令等价于 $ git pull origin master 但是使用git fetch + git merge 更加安全。 (2)git pull --rebase origin master 重定基,可以是历史更加统一,即使提交历史趋向于一条直线。 补充:他们之间的关系 git pull = git fetch + git merge FETCH_HEAD git pull --rebase = git fetch + git rebase FETCH_HEAD 如果变基失败: git add/rm 被修改的文件名 可以先修改README.md文件; 然后使用命令:git add README.md 成功之后回复变基: git rebase --continue 之后出现编辑文本,直接退出即可完成问题处理。 恢复变基 (git rebase --continue) 或中止它 (git rebase --abort)。 Vim编辑器 :q! 此命令是强制退出Vim编辑器,对文件内容不作处理,不管改动过还是未改动.