转载于https://blog.csdn.net/qq_24815615/article/details/70227385
原文地址https://www.eemaker.com/stm32cubemxadc.html
单片机为:STM32F103RCT6
软件:STM32CubeMX,MDK
功能:不使用DMA,不使用中断,读取ADC1内部温度传感器及内部参照电压VREFINT的值
描述:温度传感器和通道ADC1_IN16相连接,内部参照电压VREFINT和ADC1_IN17相连接。可以按注入或规则通道对这两个内部通道进行转换。注意: 温度传感器和VREFINT只能出现在主ADC1中。
内部温度传感器温度计算公式:
温度C = (V25 - Vsence)/Avg_Slope + 25
V25 = Vsence在25°C时的数值,典型值为1.43V
Avg_Slope = 温度与VSENSE曲线的平均斜率(单位为mV/ °C 或 μV/ °C),典型值为4.3mv/C
Vsence为读取内部温度传感器的AD值3.3/4096
所以最终公式为:
C = (1.43 - tempadc3.3/4096)*1000/4.3 + 25;
ADC采集的几个概念:
扫描模式(想采集多通道必须开启):是一次对所选中的通道进行转换,比如开了ch0,ch1,ch4,ch5。ch0转换完以后就会自动转换通道1,4,5直到转换完。但是这种连续性并不是不能被打断。这就引入了间断模式。
间断模式:可以说是对扫描模式的一种补充。它可以把0,1,4,5这四个通道进行分组。可以分成0,1一组,4,5一组。也可以每个通道配置为一组。这样每一组转换之前都需要先触发一次。
单次模式和连续模式:这两中模式的概念是相对应的。这里的单次模式并不是指一个通道。假如你同时开了ch0,ch1,ch4,ch5这四个通道。单次模式转换模式下会把这四个通道采集一边就停止了。而连续模式就是这四个通道转换完以后再循环过来再从ch0开始。
规则组和注入组:规则通道相当于你正常运行的程序,而注入通道就相当于中断。即注入通道的转换可以打断规则通道的转换, 在注入通道被转换完成之后,规则通道才得以继续转换。
下面配置CubeMx来生成程序:
1,选择ADC1的通道
2,配置ADC1的参数
经过测试,要想用非dma和非中断模式只有这样配置可以正确进行多通道转换:扫描模式+单次转换模式+间断转换模式(每个间断组一个通道)。
分析配置成这样的模式,扫描模式是在配置为多个通道必须打开的,stm32cubeMX上也默认好了,只能enable。单次转换模式是我不需要不停的去采集每个通道值,而是把2个通道采集完以后就让它停止。这里间断配置是关键,间断模式可以让扫描的2个通道进行分成2个组,stm32cubeMX参数里面number of Discontinous Conversions是配置间断组每个组有几个通道的,这里必须配置为1(否则在获取ad值得时候只能读取到每个间断组最后一个通道)。
生成mdk工程代码。初始化ADC代码如下:
ADC_HandleTypeDef hadc1;
/* ADC1 init function */
void MX_ADC1_Init(void)
{
ADC_ChannelConfTypeDef sConfig;
/**Common config
*/
hadc1.Instance = ADC1;
hadc1.Init.ScanConvMode = ADC_SCAN_ENABLE;
hadc1.Init.ContinuousConvMode = DISABLE;
hadc1.Init.DiscontinuousConvMode = ENABLE;
hadc1.Init.NbrOfDiscConversion = 1;
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.NbrOfConversion = 2;
if (HAL_ADC_Init(&hadc1) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
/**Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_VREFINT;
sConfig.Rank = 1;
sConfig.SamplingTime = ADC_SAMPLETIME_239CYCLES_5;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
/**Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_TEMPSENSOR;
sConfig.Rank = 2;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
}
这时候还没有完成,只是实现了ADC的初始化,需要采集这2个通道值得函数还要自己写。下面就采集这2个通道的函数:
uint8_t Get_Adc_Val(uint16_t *V, uint16_t *T)
{
uint16_t adc[2];
uint8_t i;
for(i=0; i<2; i++)
{
HAL_ADC_Start(&hadc1);
if(HAL_ADC_PollForConversion(&hadc1, 1000) == HAL_OK)
{
adc[i] = HAL_ADC_GetValue(&hadc1);
}
}
HAL_ADC_Stop(&hadc1);
*V = adc[0];
*T = adc[1];
return 0;
}
调用hal库接口函数也需要注意,HAL_ADC_Start一定要放在for里面,即每一个通道都要触发。2个通道都采集完了,再去调用HAL_ADC_Stop(&hadc1); 结束本次ADC采集。
最后说下,这个是针对stm32F103系列的芯片,其他型号的配置可能略有不同,大体思路一样