4.1.1 调时钟,要选外部高速源HSE(24MHz晶振),右边填170MHz后Cube软件会自动生成选择方案。
4.1.2 先用定时器TIM1产生一个20KHz,正占空比为20%的PWM波。配置如下:使能内部时钟、打开通道1、参数如图配置。预分频PSC和Counter Period实际计算会算上0所以要-1。为方便配占空比设计数周期为10次,Pulse设为2。
频率为 170MHz/850/10 = 20KHz。
在PWM mode 1、Upcounting计数模式下,Counter Period参数存入寄存器ARR(Auto Reload Register),Pulse参数存入寄存器CCR(Capture Compare Register),参照用户手册中下图。本例中计数值为9,Pulse值为2,则0~9中小于2的部分0、1为高电平,2~9为低电平,使正占空比为20%。
4.1.3 MDK中代码需调用此函数打开PWM输出。
4.1.4 示波器验证效果成功实现。
4.2 再用定时器以1KHz频率触发ADC转换芯片内部温度传感器数据,用DMA存储,并通过串口发送温度校正值。
4.2.1 打开TIM6调参数使频率为 170MHz/170/1000 = 1KHz。然后打开ADC1的Temperature Sensor和Vrefint(内部参考电压)通道,设为扫描、非连续模式,用TIM6触发。
4.2.2 添加DMA用于将ADC采集数据存入内存,设为循环模式,因为ADC1是12位所以内存地址每次增加16位,设为Half Word。DMA将会在内存某处环形缓冲区(设为 u16 ADC_Data[20] ,两个通道各取十次测量值,计算中/10取平均值)循环往复写入数据,如图是一次循环的内存快照,下次循环从base重新开始写入。
//取数据部分代码
ADC_TS = 0;
ADC_VREFINT = 0;
for(u8 i=0; i<20; ){
ADC_TS += ADC_Data[i++];
ADC_VREFINT += ADC_Data[i++];
}
ADC_TS /= 10;
ADC_VREFINT /= 10;
再在main()中调用此函数即可打开DMA:
4.2.2 MDK中代码需要调用这个函数打开定时器TIM6。
4.2.3 ①在用户手册中研究温度校正和内部参考电压校正,得到以下两个公式:
②在stm32g4xx_II_adc.c中找到以上两公式的计算宏
/**
* @brief Helper macro to calculate analog reference voltage (Vref+)
* (unit: mVolt) from ADC conversion data of internal voltage
* reference VrefInt.
* @note Computation is using VrefInt calibration value
* stored in system memory for each device during production.
* @note This voltage depends on user board environment: voltage level
* connected to pin Vref+.
* On devices with small package, the pin Vref+ is not present
* and internally bonded to pin Vdda.
* @note On this STM32 series, calibration data of internal voltage reference
* VrefInt corresponds to a resolution of 12 bits,
* this is the recommended ADC resolution to convert voltage of
* internal voltage reference VrefInt.
* Otherwise, this macro performs the processing to scale
* ADC conversion data to 12 bits.
* @param __VREFINT_ADC_DATA__ ADC conversion data (resolution 12 bits)
* of internal voltage reference VrefInt (unit: digital value).
* @param __ADC_RESOLUTION__ This parameter can be one of the following values:
* @arg @ref LL_ADC_RESOLUTION_12B
* @arg @ref LL_ADC_RESOLUTION_10B
* @arg @ref LL_ADC_RESOLUTION_8B
* @arg @ref LL_ADC_RESOLUTION_6B
* @retval Analog reference voltage (unit: mV)
*/
#define __LL_ADC_CALC_VREFANALOG_VOLTAGE(__VREFINT_ADC_DATA__,\
__ADC_RESOLUTION__) \
(((uint32_t)(*VREFINT_CAL_ADDR) * VREFINT_CAL_VREF) \
/ __LL_ADC_CONVERT_DATA_RESOLUTION((__VREFINT_ADC_DATA__), \
(__ADC_RESOLUTION__), \
LL_ADC_RESOLUTION_12B))
/**
* @brief Helper macro to calculate the temperature (unit: degree Celsius)
* from ADC conversion data of internal temperature sensor.
* @note Computation is using temperature sensor calibration values
* stored in system memory for each device during production.
* @note Calculation formula:
* Temperature = ((TS_ADC_DATA - TS_CAL1)
* * (TS_CAL2_TEMP - TS_CAL1_TEMP))
* / (TS_CAL2 - TS_CAL1) + TS_CAL1_TEMP
* with TS_ADC_DATA = temperature sensor raw data measured by ADC
* Avg_Slope = (TS_CAL2 - TS_CAL1)
* / (TS_CAL2_TEMP - TS_CAL1_TEMP)
* TS_CAL1 = equivalent TS_ADC_DATA at temperature
* TEMP_DEGC_CAL1 (calibrated in factory)
* TS_CAL2 = equivalent TS_ADC_DATA at temperature
* TEMP_DEGC_CAL2 (calibrated in factory)
* Caution: Calculation relevancy under reserve that calibration
* parameters are correct (address and data).
* To calculate temperature using temperature sensor
* datasheet typical values (generic values less, therefore
* less accurate than calibrated values),
* use helper macro @ref __LL_ADC_CALC_TEMPERATURE_TYP_PARAMS().
* @note As calculation input, the analog reference voltage (Vref+) must be
* defined as it impacts the ADC LSB equivalent voltage.
* @note Analog reference voltage (Vref+) must be either known from
* user board environment or can be calculated using ADC measurement
* and ADC helper macro @ref __LL_ADC_CALC_VREFANALOG_VOLTAGE().
* @note On this STM32 series, calibration data of temperature sensor
* corresponds to a resolution of 12 bits,
* this is the recommended ADC resolution to convert voltage of
* temperature sensor.
* Otherwise, this macro performs the processing to scale
* ADC conversion data to 12 bits.
* @param __VREFANALOG_VOLTAGE__ Analog reference voltage (unit: mV)
* @param __TEMPSENSOR_ADC_DATA__ ADC conversion data of internal
* temperature sensor (unit: digital value).
* @param __ADC_RESOLUTION__ ADC resolution at which internal temperature
* sensor voltage has been measured.
* This parameter can be one of the following values:
* @arg @ref LL_ADC_RESOLUTION_12B
* @arg @ref LL_ADC_RESOLUTION_10B
* @arg @ref LL_ADC_RESOLUTION_8B
* @arg @ref LL_ADC_RESOLUTION_6B
* @retval Temperature (unit: degree Celsius)
*/
#define __LL_ADC_CALC_TEMPERATURE(__VREFANALOG_VOLTAGE__,\
__TEMPSENSOR_ADC_DATA__,\
__ADC_RESOLUTION__) \
(((( ((int32_t)((__LL_ADC_CONVERT_DATA_RESOLUTION((__TEMPSENSOR_ADC_DATA__), \
(__ADC_RESOLUTION__), \
LL_ADC_RESOLUTION_12B) \
* (__VREFANALOG_VOLTAGE__)) \
/ TEMPSENSOR_CAL_VREFANALOG) \
- (int32_t) *TEMPSENSOR_CAL1_ADDR) \
) * (int32_t)(TEMPSENSOR_CAL2_TEMP - TEMPSENSOR_CAL1_TEMP) \
) / (int32_t)((int32_t)*TEMPSENSOR_CAL2_ADDR - (int32_t)*TEMPSENSOR_CAL1_ADDR) \
) + TEMPSENSOR_CAL1_TEMP \
)
③通过串口打印结果,仍用TaskProcess()函数,以下是部分定义和实际功能函数代码。
//部分定义
/* USER CODE BEGIN PTD */
#define MCL_MAX 2
#define __VREFINT_ADC_DATA__ (ADC_VREFINT/10)
#define __ADC_RESOLUTION__ (LL_ADC_RESOLUTION_12B)
#define __VREFANALOG_VOLTAGE__ (__HAL_ADC_CALC_VREFANALOG_VOLTAGE(__VREFINT_ADC_DATA__,\
__ADC_RESOLUTION__))
#define __TEMPSENSOR_ADC_DATA__ (ADC_TS/10)
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
vu32 OSTick = 0;
u16 ADC_Data[2*10]; //两组测十次取平均值.
u32 ADC_TS, ADC_VREFINT;
static void App_EndProcess(void);
void TimingDelay_Decrement(void);
void SetMacbRemarks(u16 dif);
static void TaskProcess(void);
void TP_Send(void);
/* USER CODE END PD */
void TP_Send(void)
{
ADC_TS = 0;
ADC_VREFINT = 0;
for(u8 i=0; i<20; ){
ADC_TS += ADC_Data[i++];
ADC_VREFINT += ADC_Data[i++];
}
printf("TS_ADC_DATA = %d \n", (ADC_TS/10));
printf("__VREFINT_ADC_DATA__ = %d \n", (ADC_VREFINT/10));
printf("__HAL_ADC_CALC_VREFANALOG_VOLTAGE = %lu\n",
__HAL_ADC_CALC_VREFANALOG_VOLTAGE(__VREFINT_ADC_DATA__,\
__ADC_RESOLUTION__));
printf("__HAL_ADC_CALC_TEMPERATURE = %lu\n",
__HAL_ADC_CALC_TEMPERATURE(__VREFANALOG_VOLTAGE__,\
__TEMPSENSOR_ADC_DATA__,\
__ADC_RESOLUTION__));
}
4.2.4 在串口调试助手上验证结果: