设计采用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[2] = { 0, 0 };
-
- // 读取采样点
- adc_data[0] = ADC1_GetBufferValue(0x00);
- adc_data[1] = ADC1_GetBufferValue(0x01);
-
- // 采样数据处理
- m_x_sen_sum += adc_data[0];
- m_y_sen_sum += adc_data[1];
- // 清除中断标志
- 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[8] = {0,0,0,0,0,0,0,0};
ADC1_IRQ_Count++;
//samp_times++;
// Get the ADC value of every channel
adc_data[0] = ADC1_GetBufferValue(0x00);
adc_data[1] = ADC1_GetBufferValue(0x01);
adc_data[2] = ADC1_GetBufferValue(0x02);
adc_data[3] = ADC1_GetBufferValue(0x03);
adc_data[4] = ADC1_GetBufferValue(0x04);
adc_data[5] = ADC1_GetBufferValue(0x05);
adc_data[6] = ADC1_GetBufferValue(0x06);
adc_data[7] = ADC1_GetBufferValue(0x07);
//sum of ADC value of every channel
channel0_adc_value_sum += adc_data[0];
channel1_adc_value_sum += adc_data[1];
channel2_adc_value_sum += adc_data[2];
channel3_adc_value_sum += adc_data[3];
channel4_adc_value_sum += adc_data[4];
channel5_adc_value_sum += adc_data[5];
channel6_adc_value_sum += adc_data[6];
channel7_adc_value_sum += adc_data[7];
// 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[8],ADC_Val_Sum[8]更好,不用写这么多次
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();
}
}
}
一是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多通道连续扫描问题
输入这个值,是说明关闭AIN1,我理解这里不采集哪些就直接输入哪些就可以了,如下:
ADC1_SCHMITTTRIG_CHANNEL2|ADC1_SCHMITTTRIG_CHANNEL3
想请教大神两个问题:
1.这个8各通道转换后的数据是按照什么顺序存储在数据缓冲区的呢
2,我可以只扫描0通道和2通道吗?不管一通道的事......谢谢大神了
第二个问题:按照STM8S官方参考手册,如果是连续扫描,应该是0-2之间所有通道都扫描,不管你需不需要AIN1的数据,AIN1所在的IO口都不可以设置为输出状态,因为这个IO口的输出功能被禁止了,所以扫描模式的话还是建议用连续的模拟通道,中间不要断开,不然的话就不要用扫描吧,直接单次转换,这是我个人的理解,希望能帮到你,你自己也可以多测试下!
[img]file:///C:\Users\Administrator\AppData\Roaming\Tencent\Users\545483362\QQ\WinTemp\RichOle\[Q9YMLL[0QMIEDEZR%)DU3S.png[/img]
ADC扫描模式时IO状态
按您的提示 成功了 需要重新载入扫描系列新的最后的通道号 这步是关键
赞赞赞