问题遇到的现象和发生背景
MSP430F5529LP ADC四通道循环采样中断标志位无法清除,导致不断进入采样,阻碍主函数运行
参考外部按键中断的服务函数,有一个清除中断标志位的功能,但是在ADC中断里面不行。
全国大学生电子设计竞赛
问题相关代码
#include "driverlib.h"
#include "oled.h"
#include "pwm_a_init.h"
#include "Servo.h"
//Needs to be global in this example
//Otherwise, the compiler removes it
//because it is not used for anything.
volatile uint16_t results[4];
void ADC_Test(void)
{
//Stop Watchdog Timer
// WDT_A_hold(WDT_A_BASE);
//Enable A/D channel inputs
GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P6,
GPIO_PIN0 + GPIO_PIN1 + GPIO_PIN2 +
GPIO_PIN3 + GPIO_PIN4 + GPIO_PIN5 +
GPIO_PIN6 + GPIO_PIN7
);
//Initialize the ADC12_A Module
/*
* Base address of ADC12_A Module
* Use internal ADC12_A bit as sample/hold signal to start conversion
* USE MODOSC 5MHZ Digital Oscillator as clock source
* Use default clock divider of 1
*/
ADC12_A_init(ADC12_A_BASE,
ADC12_A_SAMPLEHOLDSOURCE_SC,
ADC12_A_CLOCKSOURCE_ADC12OSC,
ADC12_A_CLOCKDIVIDER_1);
ADC12_A_enable(ADC12_A_BASE);
/*
* Base address of ADC12_A Module
* For memory buffers 0-7 sample/hold for 16 clock cycles
* For memory buffers 8-15 sample/hold for 4 clock cycles (default)
* Enable Multiple Sampling
*/
// ADC12_A_setupSamplingTimer(ADC12_A_BASE,
// ADC12_A_CYCLEHOLD_16_CYCLES,
// ADC12_A_CYCLEHOLD_4_CYCLES,
// ADC12_A_MULTIPLESAMPLESENABLE);
ADC12_A_setupSamplingTimer(ADC12_A_BASE,
ADC12_A_CYCLEHOLD_16_CYCLES,
ADC12_A_CYCLEHOLD_4_CYCLES,
500);
//Configure Memory Buffers
/*
* Base address of the ADC12_A Module
* Configure memory buffer 0
* Map input A0 to memory buffer 0
* Vref+ = AVcc
* Vref- = AVss
* Memory buffer 0 is not the end of a sequence
*/
ADC12_A_configureMemoryParam param0 = {0};
param0.memoryBufferControlIndex = ADC12_A_MEMORY_0;
param0.inputSourceSelect = ADC12_A_INPUT_A0;
param0.positiveRefVoltageSourceSelect = ADC12_A_VREFPOS_AVCC;
param0.negativeRefVoltageSourceSelect = ADC12_A_VREFNEG_AVSS;
param0.endOfSequence = ADC12_A_NOTENDOFSEQUENCE;
ADC12_A_configureMemory(ADC12_A_BASE ,¶m0);
/*
* Base address of the ADC12_A Module
* Configure memory buffer 1
* Map input A1 to memory buffer 1
* Vref+ = AVcc
* Vref- = AVss
* Memory buffer 1 is not the end of a sequence
*/
ADC12_A_configureMemoryParam param1 = {0};
param1.memoryBufferControlIndex = ADC12_A_MEMORY_1;
param1.inputSourceSelect = ADC12_A_INPUT_A1;
param1.positiveRefVoltageSourceSelect = ADC12_A_VREFPOS_AVCC;
param1.negativeRefVoltageSourceSelect = ADC12_A_VREFNEG_AVSS;
param1.endOfSequence = ADC12_A_NOTENDOFSEQUENCE;
ADC12_A_configureMemory(ADC12_A_BASE ,¶m1);
/*
* Base address of the ADC12_A Module
* Configure memory buffer 2
* Map input A2 to memory buffer 2
* Vref+ = AVcc
* Vref- = AVss
* Memory buffer 2 is not the end of a sequence
*/
ADC12_A_configureMemoryParam param2 = {0};
param2.memoryBufferControlIndex = ADC12_A_MEMORY_2;
param2.inputSourceSelect = ADC12_A_INPUT_A2;
param2.positiveRefVoltageSourceSelect = ADC12_A_VREFPOS_AVCC;
param2.negativeRefVoltageSourceSelect = ADC12_A_VREFNEG_AVSS;
param2.endOfSequence = ADC12_A_NOTENDOFSEQUENCE;
ADC12_A_configureMemory(ADC12_A_BASE ,¶m2);
/*
* Base address of the ADC12_A Module
* Configure memory buffer 3
* Map input A3 to memory buffer 3
* Vr+ = AVcc
* Vr- = AVss
* Memory buffer 3 IS the end of a sequence
*/
ADC12_A_configureMemoryParam param3 = {0};
param3.memoryBufferControlIndex = ADC12_A_MEMORY_3;
param3.inputSourceSelect = ADC12_A_INPUT_A3;
param3.positiveRefVoltageSourceSelect = ADC12_A_VREFPOS_AVCC;
param3.negativeRefVoltageSourceSelect = ADC12_A_VREFNEG_AVSS;
param3.endOfSequence = ADC12_A_ENDOFSEQUENCE;
ADC12_A_configureMemory(ADC12_A_BASE ,¶m3);
//Enable memory buffer 3 interrupt
ADC12_A_clearInterrupt(ADC12_A_BASE,
ADC12IE3);
ADC12_A_enableInterrupt(ADC12_A_BASE,
ADC12IE3);
while (1)
{
//Enable/Start first sampling and conversion cycle
/*
* Base address of ADC12_A Module
* Start the conversion into memory buffer 0
* Use the repeated sequence of channels
*/
ADC12_A_startConversion(ADC12_A_BASE,
ADC12_A_MEMORY_0,
ADC12_A_SEQOFCHANNELS);
//Enter LPM4, Enable interrupts
__bis_SR_register(LPM4_bits + GIE);
//For debugger
__no_operation();
}
}
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=ADC12_VECTOR
__interrupt
#elif defined(__GNUC__)
__attribute__((interrupt(ADC12_VECTOR)))
#endif
void ADC12ISR (void)
{
// _EINT();
switch (__even_in_range(ADC12IV,34)){
case 0: break; //Vector 0: No interrupt
case 2: break; //Vector 2: ADC overflow
case 4: break; //Vector 4: ADC timing overflow
case 6: break; //Vector 6: ADC12IFG0
case 8: break; //Vector 8: ADC12IFG1
case 10: break; //Vector 10: ADC12IFG2
case 12: //Vector 12: ADC12IFG3
//Move results, IFG is cleared
//result 0 1 2 3是四个A
results[0] =
ADC12_A_getResults(ADC12_A_BASE,//舵机占空比满值为327
ADC12_A_MEMORY_0);
OLED_ShowNum(1,1 ,results[0],4,10);
Set_PWMS((int)results[0]*1.0/10*1.8);
OLED_ShowString(45,1,"PWMS",8);
OLED_ShowNum(79,1,(int)1.0*results[0]/10*1.8,4,8);
//
//Move results, IFG is cleared
results[1] =
ADC12_A_getResults(ADC12_A_BASE,
ADC12_A_MEMORY_1);
OLED_ShowNum(1,2,results[1],4,10);
//Move results, IFG is cleared
results[2] =
ADC12_A_getResults(ADC12_A_BASE,
ADC12_A_MEMORY_2);
OLED_ShowNum(1,3 ,results[2],4,10);
//Move results, IFG is cleared
results[3] =
ADC12_A_getResults(ADC12_A_BASE,
ADC12_A_MEMORY_3);
OLED_ShowNum(1,4,results[3],4,10);
//Exit active CPU, SET BREAKPOINT HERE
__bic_SR_register_on_exit(LPM4_bits);
case 14: break; //Vector 14: ADC12IFG4
case 16: break; //Vector 16: ADC12IFG5
case 18: break; //Vector 18: ADC12IFG6
case 20: break; //Vector 20: ADC12IFG7
case 22: break; //Vector 22: ADC12IFG8
case 24: break; //Vector 24: ADC12IFG9
case 26: break; //Vector 26: ADC12IFG10
case 28: break; //Vector 28: ADC12IFG11
case 30: break; //Vector 30: ADC12IFG12
case 32: break; //Vector 32: ADC12IFG13
case 34: break; //Vector 34: ADC12IFG14
default: break;
}
// ADC12IFG0_L=~BIT0;
// ADC12IFG1_L=
// ADC12IFG2_L=
// ADC12IFG3_L=0x00;
//此处尝试仿照外部中断,清除ADC中断标志位
}
运行结果及报错内容
"../ADC.c", line 199: error #138: expression must be a modifiable lvalue
我的解答思路和尝试过的方法
#pragma vector=PORT1_VECTOR
__interrupt void P1_ISR(void)
{
// _EINT();
if(P1IFG & BIT5)
{
signal_count_A++;
signal_count_A%=1000;
OLED_ShowString(1,6,"A",8);
OLED_ShowNum(34,6,signal_count_A,4,7);
}
P1IFG &=~BIT5;//清空中断标志
}
参考了这个清除外部P1.5中断标志位的方法,但是对于ADC中断没有成功
我想要达到的结果
可以加入清除ADC中断标志位的代码
防止ADC采样的中断服务函数不断自己进入,阻碍主函数运行
源代码已上传至百度网盘:
链接:https://pan.baidu.com/s/1XpmUtEjNPQTybTNvG9_l6A?pwd=msp4
提取码:msp4
QQ:2861173454
没用过这个
这种程序写法好多寄存器配置不太看的懂,根据看到的写一下吧。
1、ADC12有四种转换模式:单通道一次;序列通道一次;单通道重复;序列通道重复。没有看出模式选择,寄存器默认应该是单通道一次。
2、while循环中一直在开始转换,转换时间可能不够,建议中断计时,时间到置标志到主函数里去转换。
3、430的ADC12的中断标志位不用清除,当对应通道采样结束后,采样结果存于相应的ADC12MEMx中后,相应的中断标志位被置位,待读取采样结果ADFC12MEMx后,采样中断标志位被硬件自动清零!! 因此,在发生采样中断后,必须读取采样结果(同时自动清除采样中断标志),然后才能继续进行采样!
4、建议参考看看手册,可以参考一下这种程序写法,个人认为直接控制寄存器清楚一些。https://blog.csdn.net/qq_51518393/article/details/119821167