/* p7_2.c: On-chip temperature sensor * This program converts the on-chip temperature sensor output * and display the temperature in Celsius on the console. * Timer TIM3 is configured to generate 1 Hz output, which is * used to trigger the A/D conversion. The internal temperature * sensor is connected to channel 16 of ADC1 Master. The sensor * is turned on at bit 23 of ADC_CCR register. * * The conversion result is displayed as Celsius on the console * using the formula and parameters in the datasheet. * The console UART driver is from Program 4-5. * * This program was tested with Keil uVision v5.23 with DFP v2.0.0. */ #include "stm32f0xx.h" #include /* Temperature sensor calibration value address */ #define TEMP30_CAL_ADDR ((uint16_t*)((uint32_t)0x1FFFF7B8)) // The ADC value in 30 degrees Celsius saved here by factory #define TEMP110_CAL_ADDR ((uint16_t*)((uint32_t)0x1FFFF7C2)) // The ADC value in 110 degrees Celsius saved here by factory void USART2_init(void); int USART2_write(int c); int main(void) { uint32_t data; double temp, y1, y2, x1, x2, m; /* will contain the temperature in degrees Celsius */ RCC->AHBENR |= 0x00020000; /* enable GPIOA clock */ /* setup TIM3 */ RCC->APB1ENR |= 0x00000002; /* enable TIM3 clock */ TIM3->PSC = 800 - 1; /* divided by 800 */ TIM3->ARR = 10000 - 1; /* divided by 10000, sample at 1 Hz */ TIM3->CNT = 0; TIM3->CCMR1 = 0x00006800; /* pwm1 mode, preload enable */ TIM3->CCER = 0x0010; /* ch2 enable */ TIM3->CCR2 = 50 - 1; TIM3->CR2 = 0x00000020; /* The update event is selected as trigger output */ TIM3->CR1 = 1; /* enable timer3 */ /* setup ADC1 */ RCC->APB2ENR |= 0x00000200; /* enable ADC1 clock */ /* calibrate ADC*/ ADC1->CR = 0x80000000; while(ADC1->CR & 0x80000000); /* turn on the temp sensor */ /* configure A to D converter */ ADC1->CHSELR = (1 << 16); /* ch16 - internal temp sensor, single channel */ ADC1->SMPR = 0x00000007; /* Select a sampling mode of 239.5 ADC clk to be greater than 17.1us */ ADC->CCR |= (1 << 23); ADC1->CFGR1 = 0x000004C0; /* trigger: EXTEN rising edge, EXTSEL 3 = TIM3_TRGO */ ADC1->CFGR2 = 0; ADC1->CR |= 1; /* enable ADC1 */ /* initialize USART2 for output */ USART2_init(); printf("ADC internal temperature sensor \r\n"); y1 = 30; y2 = 110; x1 = *TEMP30_CAL_ADDR; x2 = *TEMP110_CAL_ADDR; m = (y2 - y1)/(x2-x1); ADC1->CR |= 0x00000004; /* start a conversion */ while (1) { while (!(ADC1->ISR & 4)) { } ADC1->ISR = 0xFFFF; data = ADC1->DR; temp = m*((double)data - x1) + y1; /* Calculate temperature */ printf("%d, %.2f%cC\r\n", data, temp, 176); /* octal 176 is degree sign in ASCII */ } } /* initialize USART2 to transmit at 9600 Baud */ void USART2_init(void) { RCC->AHBENR |= 0x00020000; /* Enable GPIOA clock */ RCC->APB1ENR |= 0x00020000; /* Enable USART2 clock */ /* Configure PA2, PA3 for USART2 TX, RX */ GPIOA->AFR[0] &= ~0xFF00; GPIOA->AFR[0] |= 0x1100; /* alt1 for USART2 */ GPIOA->MODER &= ~0x00F0; GPIOA->MODER |= 0x00A0; /* enable alt. function for PA2, PA3 */ USART2->BRR = 0x0341; /* 9600 baud @ 8 MHz */ USART2->CR1 = 0x000C; /* enable Tx, Rx, 8-bit data */ USART2->CR2 = 0x0000; /* 1 stop bit */ USART2->CR3 = 0x0000; /* no flow control */ USART2->CR1 |= 0x0001; /* enable USART2 */ } /* Write a character to USART2 */ int USART2_write(int ch) { while (!(USART2->ISR & 0x0080)) { } // wait until Tx buffer empty USART2->TDR = (ch & 0xFF); return ch; } /* The code below is the interface to the C standard I/O library. * All the I/O are directed to the console, which is UART2. */ struct __FILE { int handle; }; FILE __stdout = { 1 }; /* Called by C library console/file output */ int fputc(int c, FILE *f) { return USART2_write(c); /* write the character to console */ }