1、 前言
电池在使用过程中,需要检测电量,以免出现过放等损坏电池的现象。
1.1检测方法
使用的电池为3s标称11.1V锂电池,通过电阻分压的方法,配置合适的电阻比,检测接地电阻的电压,通过AD转换将采集的电压值转换为数字量,一旦检测到电压低,报警灯亮。
1.2AD转换原理
模拟信号经过采样、量化和编码,形成离散的、能被二进制描述的数字信号的过程,称为AD转换。大家都懂哈,就不赘述了。
2、电池电量检测原理
2.2gd32引脚配置
PA1用于AD采集
PA7PA8PA10PC13分别用于电量的指示。
3、代码编写
附录中有全部源码。
- /*!
- file main.c
- brief running led demo
- version 2019-06-05, V1.0.0, demo for GD32VF103
- version 2020-12-18, V1.1.0, demo for GD32VF103
- */
- /*
- Copyright (c) 2020, GigaDevice Semiconductor Inc.
- Redistribution and use in source and binary forms, with or without modification,
- are permitted provided that the following conditions are met:
- 1. Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
- 2. Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
- 3. Neither the name of the copyright holder nor the names of its contributors
- may be used to endorse or promote products derived from this software without
- specific prior written permission.
-
- */
- #include "gd32vf103.h"
- #include "gd32vf103r_start.h"
- #include "systick.h"
- void led_init(void);
- void timer_pwm_config(void);
- void timer0_config(void);
- void AG_ADC0_init(void);
- /*!
- brief main function
- param[in] none
- param[out] none
- retval none
- */
- uint32_t interrupt_counter = 0;
- uint16_t T=0;
- uint16_t adc_value;
- float Vbat;
- void TIMER0_UP_IRQHandler(void)
- {
- if(timer_interrupt_flag_get(TIMER0, TIMER_INT_FLAG_UP)!=RESET)
- {
- timer_interrupt_flag_clear(TIMER0, TIMER_INT_FLAG_UP);
- //gpio_bit_write(GPIOA, GPIO_PIN_7, (bit_status)(1-gpio_input_bit_get(GPIOA, GPIO_PIN_7)));
- // T+=50;
- // if(T>999)
- // {
- // T=0;
- // }
- }
- }
- void ADC0_1_IRQHandler(void)
- {
- if(adc_interrupt_flag_get(ADC0, ADC_INT_FLAG_EOC) != RESET)
- {
- adc_interrupt_flag_clear(ADC0, ADC_INT_FLAG_EOC);
- adc_value = adc_regular_data_read(ADC0);
- }
- }
- int main(void)
- {
- led_init();
- eclic_global_interrupt_enable();//使能全局中断
- eclic_set_nlbits(ECLIC_GROUP_LEVEL3_PRIO1);//分组
- eclic_irq_enable(TIMER0_UP_IRQn, 1, 0);//使能中断请求--设置优先级
- //timer_pwm_config();
- timer0_config();
- AG_ADC0_init();
- while(1)
- {
- // /* turn on LED1 */
- // gpio_bit_set(GPIOA, GPIO_PIN_7);
- // /* insert 200 ms delay */
- // delay_1ms(100);
- //
- // /* turn on LED2 */
- // gpio_bit_set(GPIOA, GPIO_PIN_8);
- // /* insert 200 ms delay */
- // delay_1ms(200);
- //
- // /* turn on LED3 */
- // gpio_bit_set(GPIOA, GPIO_PIN_10);
- // /* insert 200 ms delay */
- // delay_1ms(300);
- //
- // /* turn on LED4 */
- // gpio_bit_set(GPIOC, GPIO_PIN_13);
- // /* insert 200 ms delay */
- // delay_1ms(400);
- //// gpio_bit_write(GPIOA, GPIO_PIN_7, (bit_status)(1-gpio_input_bit_get(GPIOA, GPIO_PIN_7)));
- //
- //
- // /* turn off LEDs */
- // gpio_bit_reset(GPIOA, GPIO_PIN_7| GPIO_PIN_8 | GPIO_PIN_10);
- // gpio_bit_reset(GPIOC, GPIO_PIN_13);
-
- adc_software_trigger_enable(ADC0, ADC_REGULAR_CHANNEL); //ADC软件触发使能
- adc_value = adc_regular_data_read(ADC0);
- Vbat=((float)adc_value/4096)*3.3f*11.1;
- if(Vbat>12.5)
- {
- gpio_bit_set(GPIOA, GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_10);
- gpio_bit_set(GPIOC, GPIO_PIN_13);
- }
- else if((Vbat>11)&&(Vbat<=12.5))
- {
- gpio_bit_reset(GPIOA, GPIO_PIN_7);
- gpio_bit_set(GPIOA, GPIO_PIN_8|GPIO_PIN_10);
- gpio_bit_set(GPIOC, GPIO_PIN_13);
- }
- else if((Vbat>10)&&(Vbat<=11))
- {
- gpio_bit_reset(GPIOA, GPIO_PIN_7|GPIO_PIN_8);
- gpio_bit_set(GPIOA, GPIO_PIN_10);
- gpio_bit_set(GPIOC, GPIO_PIN_13);
- }
- else if((Vbat>9.5)&&(Vbat<=10))
- {
- gpio_bit_reset(GPIOA, GPIO_PIN_7|GPIO_PIN_8| GPIO_PIN_10);
- gpio_bit_set(GPIOC, GPIO_PIN_13);
- }
- else if(Vbat<=9.5)
- {
- gpio_bit_reset(GPIOA, GPIO_PIN_7|GPIO_PIN_8| GPIO_PIN_10);
- gpio_bit_reset(GPIOC, GPIO_PIN_13);
- }
- delay_1ms(100);
- }
- }
- /*!
- brief initialize the LEDs
- param[in] none
- param[out] none
- retval none
- */
- void led_init(void)
- {
- /* enable the LEDs clock */
- rcu_periph_clock_enable(RCU_GPIOA);
- rcu_periph_clock_enable(RCU_GPIOC);
- /* configure LEDs GPIO port */
- gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_6);
- gpio_init(GPIOA, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_10);
- gpio_init(GPIOC, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_13);
- /* turn off LEDs */
- gpio_bit_reset(GPIOA, GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_10);
- gpio_bit_reset(GPIOC, GPIO_PIN_13);
- }
- void timer_pwm_config(void)
- {
- /* -----------------------------------------------------------------------
- TIMER2CLK is 100KHz
- TIMER2 channel0 duty cycle = (25000/ 50000)* 100 = 50%
- ----------------------------------------------------------------------- */
- timer_oc_parameter_struct timer_ocintpara;
- timer_parameter_struct timer_initpara;
- rcu_periph_clock_enable(RCU_TIMER2);
- timer_deinit(TIMER2);
- /* TIMER configuration */
- timer_initpara.prescaler = 71;
- timer_initpara.alignedmode = TIMER_COUNTER_EDGE;
- timer_initpara.counterdirection = TIMER_COUNTER_UP;
- timer_initpara.period = 49999;
- timer_initpara.clockdivision = TIMER_CKDIV_DIV1;
- timer_initpara.repetitioncounter = 0;
- timer_init(TIMER2,&timer_initpara);
- /* configure CH0 in PWM mode0 */
- timer_ocintpara.ocpolarity = TIMER_OC_POLARITY_HIGH;
- timer_ocintpara.outputstate = TIMER_CCX_ENABLE;
- timer_channel_output_config(TIMER2,TIMER_CH_0,&timer_ocintpara);
- timer_channel_output_pulse_value_config(TIMER2,TIMER_CH_0,2499);
- timer_channel_output_mode_config(TIMER2,TIMER_CH_0,TIMER_OC_MODE_PWM0);
- timer_channel_output_shadow_config(TIMER2,TIMER_CH_0,TIMER_OC_SHADOW_DISABLE);
- /* auto-reload preload enable */
- timer_auto_reload_shadow_enable(TIMER2);
- /* auto-reload preload enable */
- //timer_enable(TIMER2);
- }
- void timer0_config(void)
- {
- timer_parameter_struct timer_initpara; //定时器结构体
- rcu_periph_clock_enable(RCU_TIMER0); //使能TIMER0时钟
- timer_deinit(TIMER0);
- timer_struct_para_init(&timer_initpara); //将结构体参数变为初始值
- timer_initpara.prescaler = 10799; //预分频108MH/108=10KHz
- timer_initpara.alignedmode = TIMER_COUNTER_EDGE; //对齐模式
- timer_initpara.counterdirection = TIMER_COUNTER_UP; //计数方向
- timer_initpara.period = 999; //周期10KHz/1000=10Hz
- timer_initpara.clockdivision = TIMER_CKDIV_DIV4; //时钟分频
- timer_initpara.repetitioncounter = 0; //重复计数器
- timer_init(TIMER0, &timer_initpara);
- timer_interrupt_enable(TIMER0,TIMER_INT_UP); //使能更新中断
- //eclic_irq_enable(TIMER0_UP_IRQn,2,0); //使能中断线
- timer_enable(TIMER0);
- }
- void AG_ADC0_init(void)
- {
- rcu_periph_clock_enable(RCU_GPIOA);
- rcu_periph_clock_enable(RCU_ADC0);
- gpio_init(GPIOA, GPIO_MODE_AIN, GPIO_OSPEED_50MHZ, GPIO_PIN_1);
- adc_deinit(ADC0);
- adc_mode_config(ADC_MODE_FREE); //配置ADC同步模式
- adc_mode_config(ADC_DAUL_REGULAL_FOLLOWUP_FAST); //配置ADC同步模式
- adc_special_function_config(ADC0, ADC_SCAN_MODE, ENABLE); //ADC0特殊功能开启
- adc_data_alignment_config(ADC0, ADC_DATAALIGN_RIGHT); //配置ADC数据对齐方式
- adc_channel_length_config(ADC0, ADC_REGULAR_CHANNEL, 1);//配置规则通道组或注入通道组的长度 ,1个规则组
- adc_regular_channel_config(ADC0, 0, ADC_CHANNEL_1, ADC_SAMPLETIME_55POINT5);//规则组选择
- adc_external_trigger_source_config(ADC0, ADC_REGULAR_CHANNEL, ADC0_1_EXTTRIG_REGULAR_NONE); //软件触发
- adc_external_trigger_config(ADC0, ADC_REGULAR_CHANNEL, ENABLE); //配置ADC外部触发
- adc_discontinuous_mode_config(ADC0, ADC_REGULAR_CHANNEL, 1); //配置ADC间断模式
- adc_enable(ADC0);
- delay_1ms(1);
- adc_calibration_enable(ADC0); //ADC0校准复位
- }
4、参考文档
GD32VF103-START-V1.0
GD32VF103_Datasheet_Rev1.5