引脚功能
- STM8S001有三个ADC输入通道,但是分布在两个引脚,所以可以说只有两个可用的ADC。
- 分别是PD6、PD5、PD3,对应AIN6、AIN5、AIN4,分布在第一脚和第八脚。
- 我使用两个ADC
- 具有SWIM功能的第八脚,复用为AIN5;命名为IGN;
- 第一脚,配置为AIN6;命名为MOTOn;
软件配置
#define ADC_IGN_PORT GPIOD
#define ADC_IGN_PIN GPIO_PIN_5
#define ADC_MOTORn_PORT GPIOD
#define ADC_MOTORn_PIN GPIO_PIN_6
#define ADC_IGN_CHANNEL ADC1_CHANNEL_5
#define ADC_MOTORn_CHANNEL ADC1_CHANNEL_6
#define ADC_VREF_VOLTAGE (5.0) /**< 5V */
#define ADC_RESOLUTION_VALUE (1024) /**< ADC ressolution: 10bit */
/* 初始化ADC函数 */
void adc_init(void)
{
GPIO_Init_redef(ADC_IGN_PORT, ADC_IGN_PIN, GPIO_MODE_IN_FL_NO_IT);
GPIO_Init_redef(ADC_MOTORn_PORT, ADC_MOTORn_PIN, GPIO_MODE_IN_FL_NO_IT);
ADC1->CR1 &= (~ADC1_CR1_ADON);
/* Clear the align bit */
ADC1->CR2 &= (uint8_t)(~ADC1_CR2_ALIGN);
/* Configure the data alignment */
ADC1->CR2 |= ADC1_ALIGN_RIGHT;
/* Set the single conversion mode */
ADC1->CR1 &= (uint8_t)(~ADC1_CR1_CONT);
/* Clear the external trigger selection bits */
ADC1->CR2 &= (uint8_t)(~ADC1_CR2_EXTSEL);
/* Disable the selected external trigger */
ADC1->CR2 &= (uint8_t)(~ADC1_CR2_EXTTRIG);
/* Set the selected external trigger */
ADC1->CR2 |= (uint8_t)(ADC1_EXTTRIG_GPIO);
/* Clear the SPSEL bits */
ADC1->CR1 &= (uint8_t)(~ADC1_CR1_SPSEL);
/* Select the prescaler division factor according to ADC1_PrescalerSelection values */
ADC1->CR1 |= (uint8_t)(ADC1_PRESSEL_FCPU_D18);
ADC1->TDRL |= (uint8_t)0xFF;
ADC1->TDRH |= (uint8_t)0xFF;
/* Enable the ADC1 peripheral */
ADC1->CR1 |= (uint8_t)ADC1_CR1_ADON;
adc_data.curr_channel = IGN; /**< 1-MOTORn channel; 0-IGN channel */
adc_channel_set(adc_data.curr_channel);
}
/* 设置通道函数 */
void adc_channel_set(adc_channel_name_t ch)
{
ADC1->CSR &= (uint8_t)(~ADC1_CSR_CH);
if(ch == IGN){
ADC1->CSR |= (uint8_t)(ADC_IGN_CHANNEL);
}
else if(ch == MOTORn){
ADC1->CSR |= (uint8_t)(ADC_MOTORn_CHANNEL);
}
ADC1->CR1 |= (uint8_t)ADC1_CR1_ADON;
}
/* 读取原始数据函数 */
uint16_t read_adc_orig_value(void)
{
uint16_t temph = 0;
uint8_t templ = 0;
templ = ADC1->DRL;
temph = ADC1->DRH;
temph = (uint16_t)(templ | (uint16_t)(temph << (uint8_t)8));
return temph;
}
SWIM复用为ADC之后采样值不准确
- 其实并不是ADC不准确,而是外部电路导致了ADC引脚阻抗过大,从而导致采样不准确。
- 我用IGN引脚采12V的IGN电压,开始使用了220k和22k的分压电阻,导致引脚阻抗过大,采样不准确。
- 后来使用5.6k和2k,AD值已经很接近理论值了。
- 后来怕电流过大烧坏芯片,还是选择了56k和10k,AD值比理论值略高,经过线性处理后达到准确值。
以下是不通电压时的AD电压值。
也是线性的,故进行了线性换算,得出准确值。
float get_adc_voltage(adc_channel_name_t ch)
{
if(ch == IGN){
return (1.178 * adc_data.voltage_flt[ch] - 0.882);
}
else{
return (adc_data.voltage_flt[ch]);
}
}
// end
// 2019.08.10