内部に温度センサを内蔵しており、追加の部品なしにある程度の温度は知ることができる。あまり正確とはいえないが相対的に温度の動きを見るには十分
ADC1 の 16ch に繋がっている。データシート通りだが以下の手順を踏む
- ADC1_IN16 を選択する
- 17.1μs のサンプル時間にする
- ADC_CR2 の TSVREFE ビットをセットする
- 温度センサおよびV_{REFINT}がパワーオンする
- ADON で変換する
- V_{SENSE} を読みだす
- 温度(℃) = (V_{25} - V_{SENSE}) / Avg_Slope + 25 を計算する
V_{25} と Avg_Slope は個別のデータシートに書いてある。STM32F103 の場合
- V_{25} : 1.34〜1.52 (typ=1.43) V
- Avg_Slope: 4.0〜4.6 (typ=4.3) mV/℃
17.1μs は、ADCクロックが12MHz なら 17.1e-6 / (1/12e6) = 205.2サイクル以上 、6MHz なら 102.6サイクル以上。どっちにしろサンプル時間レジスタは 0b111 (239.5サイクル) しかない。
static void setupADC(void) {
rccEnableADC1(true);
ADC1->CR1 = 0;
ADC1->CR2 = ADC_CR2_ADON;
ADC1->CR2 = ADC_CR2_ADON | ADC_CR2_RSTCAL;
while ((ADC1->CR2 & ADC_CR2_RSTCAL) != 0) ;
ADC1->CR2 = ADC_CR2_ADON | ADC_CR2_CAL;
while ((ADC1->CR2 & ADC_CR2_CAL) != 0) ;
ADC1->SMPR1 |= (
(0b111<<ADC_SMPR1_SMP17_Pos) |
(0b111<<ADC_SMPR1_SMP16_Pos)
);
}
static uint16_t startADC(uint8_t channel) {
ADC1->CR2 |= ADC_CR2_TSVREFE;
const uint8_t count = 1;
ADC1->SQR1 = (count-1) << ADC_SQR1_L_Pos;
ADC1->SQR2 = 0;
ADC1->SQR3 = (channel & 0b11111) << ADC_SQR3_SQ1_Pos;
ADC1->CR2 |= ADC_CR2_SWSTART;
// write same bit to start conversion
ADC1->CR2 |= ADC_CR2_ADON;
while ((ADC1->SR & ADC_SR_EOC) == 0) ;
return ADC1->DR & 0xffff;
}
static float getTemp(void) {
float adc = 0;
const uint8_t len = 10;
for (int i = 0; i < len; i++) {
adc += (float)startADC(16);
}
adc /= len;
const float V_sense = adc / (float)(1<<12) * 3.3;
const float V_25 = 1.43;
const float Avg_Slope = 4.3e-3;
const float temp = (V_25 - V_sense) / Avg_Slope + 25;
return temp;
}
- トップ
-
tech
-
STM32F103 で内部温度センサを読み出す