STM8S ADC多通道连续扫描问题
设计采用STM8S105K4芯片,AIN0和AIN1分别接直流电平,配置为多通道连续扫描模式。对采样值进行200次的平均。测试中发现AIN1通道始终为零,AIN0通道正常。对照手册仔细检查了几次代码,仍未发现问题,请高手指点!程序代码如下:
main.c代码
void main ( void )
{
uint16_t x_sen_data, y_sen_data;
uint16_t cnt = 0;
CLK_SYSCLKConfig(CLK_PRESCALER_HSIDIV4);
UartInit();
AdcInit();
printf("Hello, My Board.\n");
while (1)
{
// ADC采样结束
if (TRUE == g_samp_update_flag)
{
g_samp_update_flag = FALSE;
// 进行调平处理
GetAdcValue(&x_sen_data, &y_sen_data);
printf("%d %d\n", x_sen_data, y_sen_data);
AdcInit();
}
}
}
adc.c代码
// 采样数据长度
#define DATA_LEN (200)
bool g_samp_update_flag = FALSE;
///@ 定义文件局部变量
static uint32_t m_x_sen_sum = 0;
static uint32_t m_y_sen_sum = 0;
static void delay_ms(uint32_t ms)
{
while (ms--);
}
// ADC初始化
void AdcInit(void)
{
// 配置ADC相关引脚
GPIO_Init(SCR_PORT, SCR_PIN, GPIO_MODE_OUT_PP_LOW_SLOW);
GPIO_Init(SGY_PORT, SGY_PIN, GPIO_MODE_IN_FL_NO_IT);
GPIO_Init(SGX_PORT, SGX_PIN, GPIO_MODE_IN_FL_NO_IT);
// 复位ADC1
ADC1_DeInit();
// 配置ADC1
ADC1_Init(ADC1_CONVERSIONMODE_CONTINUOUS, ADC1_CHANNEL_1, ADC1_PRESSEL_FCPU_D4,
ADC1_EXTTRIG_TIM, DISABLE, ADC1_ALIGN_RIGHT,
ADC1_SCHMITTTRIG_CHANNEL1, DISABLE);
///@ 从ADC上电到开始ADC转换要间隔7us
// 连续转换模式
ADC1_ScanModeCmd(ENABLE);
// 使能EOC中断
ADC1_ITConfig(ADC1_IT_EOCIE, ENABLE);
// 使能全局中断
enableInterrupts();
delay_ms(200);
///@ 是否够7us?也许是转换不稳定的主要原因
// Start ADC Conversion
ADC1_StartConversion();
}
// ADC中断处理程序
void AdcISR(void)
{
static uint8_t samp_times = 0;
uint16_t adc_data = { 0, 0 };
// 读取采样点
adc_data = ADC1_GetBufferValue(0x00);
adc_data = ADC1_GetBufferValue(0x01);
// 采样数据处理
m_x_sen_sum += adc_data;
m_y_sen_sum += adc_data;
// 清除中断标志
ADC1_ClearITPendingBit(ADC1_IT_EOC);
// 采样点计数
samp_times++;
if (DATA_LEN == samp_times)
{
samp_times = 0;
// g_sample_flag = FALSE;
g_samp_update_flag = TRUE;
// 关闭ADC
ADC1_Cmd(DISABLE);
}
}
// 获取ADC采样值
void GetAdcValue(uint16_t *p_data_x, uint16_t *p_data_y)
{
*p_data_x = m_x_sen_sum / DATA_LEN;
*p_data_y = m_y_sen_sum / DATA_LEN;
m_x_sen_sum = 0;
m_y_sen_sum = 0;
}
第一个问题,如下设置后:
ADC1_ScanModeCmd(ENABLE);
ADC1_DataBufferCmd(ENABLE);
ADC1_ITConfig(ADC1_IT_EOCIE, ENABLE);
enableInterrupts();当所有通道转换结束后才会进入中断,这个时候你在中断中去读取每个通道的AD值
INTERRUPT_HANDLER(ADC1_IRQHandler, 22)
{
/* In order to detect unexpected events during development,
it is recommended to set a breakpoint on the following instruction.
*/
//static uint8_t samp_times = 0;
//uint16_t adc_data = {0,0,0,0,0,0,0,0};
ADC1_IRQ_Count++;
//samp_times++;
// Get the ADC value of every channel
adc_data = ADC1_GetBufferValue(0x00);
adc_data = ADC1_GetBufferValue(0x01);
adc_data = ADC1_GetBufferValue(0x02);
adc_data = ADC1_GetBufferValue(0x03);
adc_data = ADC1_GetBufferValue(0x04);
adc_data = ADC1_GetBufferValue(0x05);
adc_data = ADC1_GetBufferValue(0x06);
adc_data = ADC1_GetBufferValue(0x07);
//sum of ADC value of every channel
channel0_adc_value_sum += adc_data;
channel1_adc_value_sum += adc_data;
channel2_adc_value_sum += adc_data;
channel3_adc_value_sum += adc_data;
channel4_adc_value_sum += adc_data;
channel5_adc_value_sum += adc_data;
channel6_adc_value_sum += adc_data;
channel7_adc_value_sum += adc_data;
// Count of the sample times
samp_times++;
// Sample times up to ADC_SAMPLE_TIMES
if (ADC_SAMPLE_TIMES == samp_times)
//if (10 == samp_times)
{
samp_times = 0;//Reset the samp_times
g_samp_update_flag = TRUE;
ADC1_Cmd(DISABLE);// Disable the ADC1
}
// Clear the interupt flag
ADC1_ClearITPendingBit(ADC1_IT_EOC);
#if 1
/* Clear the ADC1 channels */
ADC1->CSR &= (uint8_t)(~ADC1_CSR_CH);
/* Select the ADC1 channel */
ADC1->CSR |= (uint8_t)(ADC1_CHANNEL_7);
#endif
}
我是在主函数中调用如下函数去对转换得到的数据求平均
void GetAdcValue(u16 *channel0_adc1_value, u16 *channel1_adc1_value,u16 *channel2_adc1_value,u16 *channel3_adc1_value,u16 *channel4_adc1_value,u16 *channel5_adc1_value,u16 *channel6_adc1_value,u16 *channel7_adc1_value)
{
if(g_samp_update_flag==TRUE)//End of all the ADC
{
g_samp_update_flag=FALSE;
*channel0_adc1_value = channel0_adc_value_sum / ADC_SAMPLE_TIMES;
*channel1_adc1_value = channel1_adc_value_sum / ADC_SAMPLE_TIMES;
*channel2_adc1_value = channel2_adc_value_sum / ADC_SAMPLE_TIMES;
*channel3_adc1_value = channel3_adc_value_sum / ADC_SAMPLE_TIMES;
*channel4_adc1_value = channel4_adc_value_sum / ADC_SAMPLE_TIMES;
*channel5_adc1_value = channel5_adc_value_sum / ADC_SAMPLE_TIMES;
*channel6_adc1_value = channel6_adc_value_sum / ADC_SAMPLE_TIMES;
*channel7_adc1_value = channel7_adc_value_sum / ADC_SAMPLE_TIMES;
channel0_adc_value_sum=0;
channel1_adc_value_sum=0;
channel2_adc_value_sum=0;
channel3_adc_value_sum=0;
channel4_adc_value_sum=0;
channel5_adc_value_sum=0;
channel6_adc_value_sum=0;
channel7_adc_value_sum=0;
ADC1_Config();
}
}
当然,上面的参数用一个数组比如ADC_Val,ADC_Val_Sum更好,不用写这么多次
ADC配置的函数如下:
void ADC1_Config(void)
{
ADC1_DeInit();
/*-------------------CONTINUOUS mode----------------------*/
#if 1
ADC1_Init(ADC1_CONVERSIONMODE_CONTINUOUS, ADC1_CHANNEL_7, ADC1_PRESSEL_FCPU_D8,
ADC1_EXTTRIG_TIM, DISABLE, ADC1_ALIGN_RIGHT, ADC1_SCHMITTTRIG_ALL, DISABLE);
#endif
ADC1_ScanModeCmd(ENABLE);
ADC1_DataBufferCmd(ENABLE);
ADC1_ITConfig(ADC1_IT_EOCIE, ENABLE);
enableInterrupts();
DelayXms(1);
//DelayXus(20);
ADC1_StartConversion();
}
延时函数:
void DelayXus(u16 cnt)
{
while(cnt--)
{
nop();
nop();
nop();
nop();
}
}
void DelayXms(u16 cnt)
{
u16 i;
while(cnt--)
{
for(i=0;i<1000;i++)
{
nop();
nop();
nop();
nop();
}
}
}
楼主您好,我今天用连续扫描模式调通了8个模拟通道(AIN0-AIN7)的AD采集,看了下您的代码,发现有两处问题:
一是ADC初始化时,设置成模拟输入的通道应该禁止施密特触发,我是全部禁止了,如下:
#if 1
ADC1_Init(ADC1_CONVERSIONMODE_CONTINUOUS, ADC1_CHANNEL_7, ADC1_PRESSEL_FCPU_D8,
ADC1_EXTTRIG_TIM, DISABLE, ADC1_ALIGN_RIGHT, ADC1_SCHMITTTRIG_ALL, DISABLE);
#endif
你可以调用库函数ADC1_SchmittTriggerConfig(ADC1_SchmittTrigg_TypeDef ADC1_SchmittTriggerChannel, FunctionalState NewState)去禁止你用于模拟输入的两个通道;
二是在中断后没有重新载入扫描系列新的最后的通道号,比如我的如下:
// Clear the interupt flag
ADC1_ClearITPendingBit(ADC1_IT_EOC);
#if 1
/* Clear the ADC1 channels */
ADC1->CSR &= (uint8_t)(~ADC1_CSR_CH);
/* Select the ADC1 channel */
ADC1->CSR |= (uint8_t)(ADC1_CHANNEL_7);
#endif
希望能对你有帮助,谢谢!
RE:STM8S ADC多通道连续扫描问题
ADC1_SCHMITTTRIG_CHANNEL1= (uint8_t)0x01, /**< Schmitt trigger disable on AIN1 */输入这个值,是说明关闭AIN1,我理解这里不采集哪些就直接输入哪些就可以了,如下:
ADC1_SCHMITTTRIG_CHANNEL2|ADC1_SCHMITTTRIG_CHANNEL3 飞龙xyj 发表于 2015-6-30 19:01
楼主您好,我今天用连续扫描模式调通了8个模拟通道(AIN0-AIN7)的AD采集,看了下您的代码,发现有两处问题 ...
想请教大神两个问题:
1.这个8各通道转换后的数据是按照什么顺序存储在数据缓冲区的呢
2,我可以只扫描0通道和2通道吗?不管一通道的事......谢谢大神了 本帖最后由 飞龙xyj 于 2015-11-9 16:04 编辑
你好我好大家好! 发表于 2015-9-6 12:37
想请教大神两个问题:
1.这个8各通道转换后的数据是按照什么顺序存储在数据缓冲区的呢
2,我可以只扫描0 ...
第二个问题:按照STM8S官方参考手册,如果是连续扫描,应该是0-2之间所有通道都扫描,不管你需不需要AIN1的数据,AIN1所在的IO口都不可以设置为输出状态,因为这个IO口的输出功能被禁止了,所以扫描模式的话还是建议用连续的模拟通道,中间不要断开,不然的话就不要用扫描吧,直接单次转换,这是我个人的理解,希望能帮到你,你自己也可以多测试下!
file:///C:\Users\Administrator\AppData\Roaming\Tencent\Users\545483362\QQ\WinTemp\RichOle\
学习了,不知有没有人用过模拟看门狗 :):):):):) 手册提到的buffer是8个还是10个,这个到底怎么定的?草 飞龙xyj 发表于 2015-6-30 19:01
楼主您好,我今天用连续扫描模式调通了8个模拟通道(AIN0-AIN7)的AD采集,看了下您的代码,发现有两处问题 ...
按您的提示 成功了 需要重新载入扫描系列新的最后的通道号 这步是关键
赞赞赞
页:
[1]
2