基于GD32F310F8P6的电源管理板软件。设备供电系统由220V、24V组成。当220V供电时,给24V电池充电,没有220V时由24V电池供电。电源管理软件实现电源切换,充电功能,并把相关信息通过串口发送给主板。
下载问题
demo下载不了
ADC
PA0,PA1用做ADC,分别用于检测充电电流和电池电压。查看数据手册引脚定义,PA0是ADC_IN0,PA1是ADC_IN1。ADC配置为扫描模式,连续模式,使用DMA,参考电压是3.3V,分辨率8位。在调试的过程中,adc值一直是0。将PA0接到3.3V,adc值还是0。一开始怀疑是软件问题,用官方demo也是同样的结果,换另外一块板子,adc值正常。换另外一颗芯片解决了这个问题,结论是芯片问题。
#include "gd32f3x0.h"
#include "systick.h"
#include "drv_adc.h"
#define ADC_CHAN_NUM 2U
uint16_t adc_value[ADC_CHAN_NUM];
void rcu_config(void);
void gpio_config(void);
void dma_config(void);
void adc_config(void);
/*!
\brief main function
\param[in] none
\param[out] none
\retval none
*/
void adcConfig(void)
{
/* system clocks configuration */
rcu_config();
/* GPIO configuration */
gpio_config();
/* DMA configuration */
/* ADC configuration */
dma_config();
adc_config();
}
/*!
\brief configure the different system clocks
\param[in] none
\param[out] none
\retval none
*/
static void rcu_config(void)
{
/* enable GPIOC clock */
rcu_periph_clock_enable(RCU_GPIOA);
/* enable ADC clock */
rcu_periph_clock_enable(RCU_ADC);
/* enable DMA clock */
rcu_periph_clock_enable(RCU_DMA);
/* config ADC clock */
rcu_adc_clock_config(RCU_ADCCK_APB2_DIV6);
}
/*!
\brief configure the GPIO peripheral
\param[in] none
\param[out] none
\retval none
*/
static void gpio_config(void)
{
/* config the GPIO as analog mode */
gpio_mode_set(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO_PIN_0 | GPIO_PIN_1);
}
/*!
\brief configure the DMA peripheral
\param[in] none
\param[out] none
\retval none
*/
static void dma_config(void)
{
/* ADC_DMA_channel configuration */
dma_parameter_struct dma_data_parameter;
/* ADC DMA_channel configuration */
dma_deinit(DMA_CH0);
/* initialize DMA single data mode */
dma_data_parameter.periph_addr = (uint32_t)(&ADC_RDATA);
dma_data_parameter.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
dma_data_parameter.memory_addr = (uint32_t)(&adc_value);
dma_data_parameter.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
dma_data_parameter.periph_width = DMA_PERIPHERAL_WIDTH_16BIT;
dma_data_parameter.memory_width = DMA_MEMORY_WIDTH_16BIT;
dma_data_parameter.direction = DMA_PERIPHERAL_TO_MEMORY;
dma_data_parameter.number = ADC_CHAN_NUM;
dma_data_parameter.priority = DMA_PRIORITY_HIGH;
dma_init(DMA_CH0, &dma_data_parameter);
dma_circulation_enable(DMA_CH0);
/* enable DMA channel */
dma_channel_enable(DMA_CH0);
}
/*!
\brief configure the ADC peripheral
\param[in] none
\param[out] none
\retval none
*/
static void adc_config(void)
{
/* ADC continuous function enable */
adc_special_function_config(ADC_CONTINUOUS_MODE, ENABLE);
/* ADC scan function enable */
adc_special_function_config(ADC_SCAN_MODE, ENABLE);
/* ADC data alignment config */
adc_data_alignment_config(ADC_DATAALIGN_RIGHT);
adc_resolution_config(ADC_RESOLUTION_8B) ;
/* ADC channel length config */
adc_channel_length_config(ADC_REGULAR_CHANNEL, ADC_CHAN_NUM);
/* ADC regular channel config */
adc_regular_channel_config(0, ADC_CHANNEL_0, ADC_SAMPLETIME_55POINT5);
adc_regular_channel_config(1, ADC_CHANNEL_1, ADC_SAMPLETIME_55POINT5);
/* ADC trigger config */
adc_external_trigger_source_config(ADC_REGULAR_CHANNEL, ADC_EXTTRIG_REGULAR_NONE);
adc_external_trigger_config(ADC_REGULAR_CHANNEL, ENABLE);
/* enable ADC interface */
adc_enable();
delay_1ms(1U);
/* ADC calibration and reset calibration */
adc_calibration_enable();
/* ADC DMA function enable */
adc_dma_mode_enable();
/* ADC software trigger enable */
adc_software_trigger_enable(ADC_REGULAR_CHANNEL);
}
//adc值换算成电压,注意乘法溢出,stSystate.batAdc最大值是4095,不溢出
stSystate.batVolmv = stSystate.batAdc * 125400 / 40950 + 18000;
PWM
PA4用作PWM输出,用于调节充电电流。pwm占空比加大,充电电流加大。pwm标准频率为100khz。查看数据手册引脚定义,PA4复用功能4是作为TIMER13_CH0输出,可以输出pwm。
系统时钟是72Mhz,AHB时钟是72Mhz,TIMER13时钟是1Mhz,pwm频率是100khz。
/*!
\brief configure the TIMER peripheral
\param[in] none
\param[out] none
\retval none
*/
#define USER_TIMER_BASE TIMER13
#define PWM_PERIOD 100
void timer_config(void)
{
timer_oc_parameter_struct timer_ocintpara;
timer_parameter_struct timer_initpara;
rcu_periph_clock_enable(RCU_GPIOA);
/*Configure PA4(TIMER13_CH0) as alternate function*/
gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_4);
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,GPIO_PIN_4);
gpio_af_set(GPIOA, GPIO_AF_4, GPIO_PIN_4);
/*
TIMER0 configuration: generate PWM signals with different duty cycles:
TIMER0CLK = SystemCoreClock / (6+1) = 72/7 = 10MHz
pwm frequency is 10Mhz/10 = 100khz
*/
rcu_periph_clock_enable(RCU_TIMER13);
timer_deinit(USER_TIMER_BASE);
/* TIMER0 configuration */
timer_initpara.prescaler = 6;
timer_initpara.alignedmode = TIMER_COUNTER_EDGE;
timer_initpara.counterdirection = TIMER_COUNTER_UP;
timer_initpara.period = 100;
timer_initpara.clockdivision = TIMER_CKDIV_DIV1;
timer_initpara.repetitioncounter = 0;
timer_init(USER_TIMER_BASE,&timer_initpara);
/* CH0 configuration in PWM mode */
timer_ocintpara.outputstate = TIMER_CCX_ENABLE;
timer_ocintpara.outputnstate = TIMER_CCXN_DISABLE;
timer_ocintpara.ocpolarity = TIMER_OC_POLARITY_HIGH;
timer_ocintpara.ocnpolarity = TIMER_OCN_POLARITY_HIGH;
timer_ocintpara.ocidlestate = TIMER_OC_IDLE_STATE_LOW;
timer_ocintpara.ocnidlestate = TIMER_OCN_IDLE_STATE_LOW;
timer_channel_output_config(USER_TIMER_BASE,TIMER_CH_0,&timer_ocintpara);
timer_channel_output_pulse_value_config(USER_TIMER_BASE,TIMER_CH_0,1);
timer_channel_output_mode_config(USER_TIMER_BASE,TIMER_CH_0,TIMER_OC_MODE_PWM0);
timer_channel_output_shadow_config(USER_TIMER_BASE,TIMER_CH_0,TIMER_OC_SHADOW_DISABLE);
timer_primary_output_config(USER_TIMER_BASE,ENABLE);
/* auto-reload preload enable */
timer_auto_reload_shadow_enable(USER_TIMER_BASE);
timer_enable(USER_TIMER_BASE);
}
void timer13_pwm_set_duty_cycle(uint16_t duty_cycle) {
/* configure TIMER channel output pulse value */
if(duty_cycle>PWM_PERIOD)
duty_cycle = PWM_PERIOD;
timer_channel_output_pulse_value_config(TIMER13, TIMER_CH_0, duty_cycle);
}
UART
PA2,PA3用作uart。在F8中,PA2用作UART1_TX,PA3用作UART1_RX。
#define EVAL_COM USART1
#define EVAL_COM_CLK RCU_USART1
#define EVAL_COM_IRQ USART1_IRQn
#define EVAL_COM_TX_PIN GPIO_PIN_2
#define EVAL_COM_RX_PIN GPIO_PIN_3
#define EVAL_COM_GPIO_PORT GPIOA
#define EVAL_COM_GPIO_CLK RCU_GPIOA
#define EVAL_COM_AF GPIO_AF_1
static rcu_periph_enum COM_CLK[COMn] = {EVAL_COM_CLK};
static uint32_t COM_TX_PIN[COMn] = {EVAL_COM_TX_PIN};
static uint32_t COM_RX_PIN[COMn] = {EVAL_COM_RX_PIN};
uint8_t tx_data[DEBUG_MAX_SIZE];
uint16_t tx_length;
uint16_t tx_count;
void gd_eval_com_init(uint32_t com)
{
uint32_t COM_ID = 0U;
if(EVAL_COM == com){
COM_ID = 0U;
}else{
}
/* enable COM GPIO clock */
rcu_periph_clock_enable(EVAL_COM_GPIO_CLK);
/* enable USART clock */
rcu_periph_clock_enable(COM_CLK[COM_ID]);
/* connect port to USARTx_Tx */
gpio_af_set(EVAL_COM_GPIO_PORT, EVAL_COM_AF, COM_TX_PIN[COM_ID]);
/* connect port to USARTx_Rx */
gpio_af_set(EVAL_COM_GPIO_PORT, EVAL_COM_AF, COM_RX_PIN[COM_ID]);
/* configure USART Tx as alternate function push-pull */
gpio_mode_set(EVAL_COM_GPIO_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, COM_TX_PIN[COM_ID]);
gpio_output_options_set(EVAL_COM_GPIO_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_10MHZ, COM_TX_PIN[COM_ID]);
/* configure USART Rx as alternate function push-pull */
gpio_mode_set(EVAL_COM_GPIO_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, COM_RX_PIN[COM_ID]);
gpio_output_options_set(EVAL_COM_GPIO_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_10MHZ, COM_RX_PIN[COM_ID]);
/* USART configure */
usart_deinit(com);
usart_baudrate_set(com, 115200U);
usart_receive_config(com, USART_RECEIVE_ENABLE);
usart_transmit_config(com, USART_TRANSMIT_ENABLE);
usart_enable(com);
}
nvic_irq_enable(EVAL_COM_IRQ, 0, 1);
//----------------------------------------
/*!
\brief this function handles USART RBNE interrupt request and TBE interrupt request
\param[in] none
\param[out] none
\retval none
*/
void USART1_IRQHandler(void)
{
// if (RESET != usart_interrupt_flag_get(EVAL_COM, USART_INT_FLAG_RBNE)){
// /* receive data */
// rx_buffer[rx_count++] = usart_data_receive(EVAL_COM);
// if (rx_count >= rx_buffer_size){
// usart_interrupt_disable(EVAL_COM, USART_INT_RBNE);
// }
// }
if (RESET != usart_interrupt_flag_get(EVAL_COM, USART_INT_FLAG_TBE)){
/* transmit data */
usart_data_transmit(EVAL_COM, tx_data[tx_count++]);
if (tx_count >= tx_length){
usart_interrupt_disable(EVAL_COM, USART_INT_TBE);
}
}
}
void usart1_send_data(void) {
uint8_t cnt = 0;
memset(tx_data,0,sizeof(tx_data));
tx_data[cnt++] = 0xcc;
tx_data[cnt++] = 0xdd;
tx_data[cnt++] = stSystate.extPower;
tx_data[cnt++] = stSystate.discharge;
tx_data[cnt++] = stSystate.charge;
tx_data[cnt++] = stSystate.chargePwm;
tx_data[cnt++] = stSystate.chargeCurAdc & 0xff;
tx_data[cnt++] = stSystate.chargeCurAdc >> 8;
tx_data[cnt++] = stSystate.batAdc & 0xff;
tx_data[cnt++] = stSystate.batAdc >> 8;
tx_data[cnt++] = stSystate.batVolmv & 0xff;
tx_data[cnt++] = stSystate.batVolmv >> 8;
tx_data[2+0x10] = calculateChecksum(tx_data,2+0x10);
tx_length = 2+0x10+1;
tx_count = 0;
/* enable USART TBE interrupt */
usart_interrupt_enable(EVAL_COM, USART_INT_TBE);
}
充电策略
外部电源接入时,电池电压低于21V才开始充电。在调试的时候发现充电电流的特性,开始时,充电电流随pwm增加的变化不大,在某个节点,一般是占空比达到90以上,电池电压越高,该节点越往后,出现pwm加1,充电电流增加200ma-500ma的情况。 但是之后充电电流会逐渐减小。为了寻找合适的充电电流,pwm从50开始增加,检测到充电电流在800ma-1000ma范围内,则以该pwm充电。如果充电电流超过1000ma,则占空比减1充电。