如何在STM32及STM32F103RB中开启ADC_1中断(含无库NVIC操作)
Hey there, let's tackle your two questions about enabling ADC1 interrupts on STM32—one covering general methods, and the other diving into raw register-level code for Keil uVision4 and STM32F103RB. Let's break it down:
If you're using ST's standard peripheral libraries (the most common approach), follow these steps:
Enable the ADC1 interrupt source
First, tell the ADC peripheral to trigger an interrupt when a conversion completes (this uses the End of Conversion, EOC, flag). Use this library call:ADC_ITConfig(ADC1, ADC_IT_EOC, ENABLE);Turn on the ADC1 peripheral clock
The ADC won't function if its clock is disabled. Enable it via the RCC register:RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);Configure the NVIC to handle ADC1 interrupts
The Nested Vector Interrupt Controller (NVIC) needs to be set up to prioritize and route the ADC1 interrupt. Here's how to initialize it:NVIC_InitTypeDef NVIC_InitStruct; NVIC_InitStruct.NVIC_IRQChannel = ADC1_IRQn; NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0; // Adjust based on your system needs NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0; NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStruct);Implement the Interrupt Service Routine (ISR)
Finally, write the ISR to handle the interrupt. Make sure the function name matches the one defined in your startup file (this is critical—Keil relies on this name to map the interrupt):void ADC1_IRQHandler(void) { if(ADC_GetITStatus(ADC1, ADC_IT_EOC) != RESET) { // Example: Read the converted ADC value uint16_t adcResult = ADC_GetConversionValue(ADC1); // Your custom logic here (e.g., store the value, trigger an action) // Clear the interrupt flag to avoid repeated triggers ADC_ClearITPendingBit(ADC1, ADC_IT_EOC); } }
If you want to avoid library functions and work directly with registers, here's the step-by-step raw code. Double-check register addresses against the STM32F103RB reference manual—this ensures you're targeting the correct hardware:
Enable ADC1 peripheral clock
The RCC_APB2ENR register (address0x40021018) controls APB2 peripheral clocks. Set bit 9 to enable ADC1:*(volatile uint32_t*)0x40021018 |= (1 << 9);Enable ADC1 EOC interrupt
The ADC_CR1 register (address0x40012404) manages ADC interrupts. Set bit 5 to enable the EOC interrupt:*(volatile uint32_t*)0x40012404 |= (1 << 5);Configure NVIC for ADC1 interrupt
ADC1 uses IRQ number 18 (confirm this in the STM32F103RB datasheet). We need to enable the interrupt and set its priority:- Enable the interrupt in NVIC_ISER0 (address
0xE000E100—this register controls the first 32 IRQs):*(volatile uint32_t*)0xE000E100 |= (1 << 18); - Set interrupt priority (optional but recommended). Use NVIC_IPR4 (address
0xE000E410), which controls IRQs 16-19. For IRQ 18, we use bits 23:20 (each IRQ gets 4 priority bits). Here's how to set preemption/sub priority to 0:// Clear existing priority bits *(volatile uint32_t*)0xE000E410 &= ~(0xF << 20); // Set priority (adjust the 0x0 value if you need different priority levels) *(volatile uint32_t*)0xE000E410 |= (0x0 << 20);
- Enable the interrupt in NVIC_ISER0 (address
Write the raw ISR
Just like with libraries, the ISR name must match the startup file's vector table entry. Here's the bare-bones version:void ADC1_IRQHandler(void) { // Check if the EOC flag is set (ADC_SR register, address 0x40012400, bit 1) if(*(volatile uint32_t*)0x40012400 & (1 << 1)) { // Read the conversion result from ADC_DR (address 0x4001240C) uint16_t adcResult = *(volatile uint16_t*)0x4001240C; // Your custom handling logic here // Clear the EOC flag (writing 0 to bit 1, or reading DR also clears it) *(volatile uint32_t*)0x40012400 &= ~(1 << 1); } }
A quick note: When working with raw registers, always cross-reference the STM32F103RB reference manual to confirm register addresses and bit positions—small hardware variations can trip you up!
内容的提问来源于stack exchange,提问作者Muzahir Hussain

