内部に温度センサを内蔵しており、追加の部品なしにある程度の温度は知ることができる。あまり正確とはいえないが相対的に温度の動きを見るには十分
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; }