1.ADC代码到底是按照什么顺序在跑
拿这段代码举例:
void ADC0Sequence0Handler(void)
{
uint16_t i;
//
// Clear the ADC interrupt flag.
//
ADCIntClear(ADC0_BASE, 0);
//
// Read ADC Value.
//
ADCSequenceDataGet(ADC0_BASE, 0, pui32ADC0Value);
for(i = 0;i < 8;i ++)
{
sum= sum+(pui32ADC0Value[i]*3300/4096);
}
flag=1;
}
//*****************************************************************************
//
// The main application.
//
//*****************************************************************************
int
main(void)
{
//
// Set the system clock to run at 200/5=40MHz using the PLL. When
// using the ADC, you must either use the PLL or supply a 16 MHz clock
// source.
SysCtlClockSet(SYSCTL_SYSDIV_5 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN |
SYSCTL_XTAL_16MHZ);
// LCD Initial
PortFunctionInit();
lcd_init();
//
// enable processer interrupt
//
IntMasterEnable();
//
// The ADC0 peripheral must be enabled for use.
//
SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);
//
// example ADC0 is used with AIN2 on port E1.
//
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);
//
// Select the analog ADC function for these pins.
//
GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_1);
ADCSequenceConfigure(ADC0_BASE, 0, ADC_TRIGGER_PROCESSOR, 0);
ADCSequenceStepConfigure(ADC0_BASE, 0, 0, ADC_CTL_CH2);
ADCSequenceStepConfigure(ADC0_BASE, 0, 1, ADC_CTL_CH2);
ADCSequenceStepConfigure(ADC0_BASE, 0, 2, ADC_CTL_CH2);
ADCSequenceStepConfigure(ADC0_BASE, 0, 3, ADC_CTL_CH2);
ADCSequenceStepConfigure(ADC0_BASE, 0, 4, ADC_CTL_CH2);
ADCSequenceStepConfigure(ADC0_BASE, 0, 5, ADC_CTL_CH2);
ADCSequenceStepConfigure(ADC0_BASE, 0, 6, ADC_CTL_CH2);
ADCSequenceStepConfigure(ADC0_BASE, 0, 7, ADC_CTL_CH2 | ADC_CTL_IE | ADC_CTL_END);
// Interrupt Register for ADC0SS0
ADCIntRegister(ADC0_BASE,0, ADC0Sequence0Handler);
//
// enable ADC0 sequence 0 interrupt
//
ADCIntEnable(ADC0_BASE, 0);
IntEnable(INT_ADC0SS0);
//
// Since sample sequence 0 is now configured, it must be enabled.
//
ADCSequenceEnable(ADC0_BASE, 0);
//
// Clear the interrupt status flag. This is done to make sure the
// interrupt flag is cleared before we sample.
//
ADCIntClear(ADC0_BASE, 0);
char str[20];
lcd_clear();
//
// Sample the temperature sensor forever. Display the value on the
// console.
//
while(1)
{
//
// Trigger the ADC conversion.
//
ADCProcessorTrigger(ADC0_BASE, 0);
// Wait until the sample sequence has completed.
if(flag==1)
{
value=sum/8;
sprintf(str, "%d mV", value);
lcd_printf(2,1,str);
SysCtlDelay(SysCtlClockGet() / 3);
flag=0;
sum=0;
}
lcd_clear();
}
}
-
主函数(main)先运行:
-
程序从
main()
开始,先配置系统时钟、LCD以及其他外围设备(例如GPIO、ADC)。 -
然后配置ADC采样序列(Sequence 0),为通道2(AIN2)设置8个采样步骤,并将最后一个步骤配置为触发中断(使用ADC_CTL_IE | ADC_CTL_END)。
-
接着通过
ADCIntRegister
和IntEnable
注册并使能了ADC的中断服务程序ADC0Sequence0Handler
。 -
最后启用ADC采样序列,并进入一个无限循环,在循环中不断触发ADC转换。
-
-
中断触发时机:
-
在主循环中,每次调用
ADCProcessorTrigger(ADC0_BASE, 0)
后,ADC开始按照配置的8个步骤进行转换。 -
当8个采样步骤全部完成后,ADC硬件自动将中断标志置位,从而触发中断服务程序
ADC0Sequence0Handler
。
-
所以就是按照main里的顺序,然后触发ADC,ADC就开始八步采样,然后自动进入中断。
2.为什么要在中断里清除标志位
-
第一行代码
ADCIntClear(ADC0_BASE, 0);
用于清除ADC的中断标志。
原因:-
清除中断标志是为了通知硬件,“本次中断已被处理”,这样硬件才能检测到下一次ADC转换完成后的中断请求。
-
如果不清除,中断标志仍然保持在“已置位”状态,可能导致后续转换的中断无法触发或者造成重复中断。
-
所以,单片机程序不仅要符合C的代码逻辑,还与硬件有一定衔接,所以有时候可能看起来无头无尾,但是其实符合单片机内部的逻辑。