www.pudn.com > PRMCharger_V0.04.rar > main__.c, change:2008-03-09,size:67643b


/****************************************Copyright (c)************************************************** 
**                              智 能 充 电 器 开 发 小 组 
**                                     OurAVR 论坛 
**                                   QQ 群: 26052247 
** 
**                               http://www.ouravr.com/bbs 
** 
** This program was produced by the 
** CodeWizardAVR V1.24.7d Professional 
** Copyright 2008-2009 OurAVR 
** Chip type           : ATmega16 
** Program type        : Application 
** Clock frequency     : 16.000000 MHz 
** Memory model        : Small 
** External SRAM size  : 0 
** Data Stack size     : 256 
**--------------文件信息-------------------------------------------------------------------------------- 
**文   件   名: Main.c 
**创   建   人: 吕海安 
**最后修改日期: 2008年03月02日 
**描        述: 智能充电器软件 
** 
**--------------历史版本信息---------------------------------------------------------------------------- 
** 创建人: 吕海安 
** 版  本: v0.01 
** 日 期: 2008年03月02日 
** 描 述: 原始版本 
** 
**--------------当前版本修订------------------------------------------------------------------------------ 
** 修改人: 
** 日 期: 
** 描 述: 
** 
**------------------------------------------------------------------------------------------------------ 
********************************************************************************************************/ 
#include "config.h" 
	#ifndef __SLEEP_DEFINED__ 
	#define __SLEEP_DEFINED__ 
	.EQU __se_bit=0x40 
	.EQU __sm_mask=0xB0 
	.EQU __sm_powerdown=0x20 
	.EQU __sm_powersave=0x30 
	.EQU __sm_standby=0xA0 
	.EQU __sm_ext_standby=0xB0 
	.EQU __sm_adc_noise_red=0x10 
	.SET power_ctrl_reg=mcucr 
	#endif 
 
// Declare your global variables here 
INT8U P10msReq; 
INT8U P100msReq; 
 
INT8U para[230];  // 所有参数和全局变量表 
 
/********************************************************************************************************* 
** 函数名称: timer0_ovf_isr 
** 功能描述: Timer 0 overflow interrupt service routine,16.384 mS @ 16M 
** 输入参数: 无 
** 输出参数: 无 
********************************************************************************************************/ 
interrupt [TIM0_OVF] void timer0_ovf_isr(void) 
{ 
    static INT16U t0count1; 
    Disable(); 
    t0count1++; 
    P10msReq = 1; // 16.384 mS 
    if(t0count1 >= 6) // about 100 mS 
    { 
        t0count1 = 0; 
        P100msReq = 1; 
    } 
    Enable(); 
} 
/********************************************************************************************************* 
** 函数名称: InitCPU 
** 功能描述: 初始化I/O端口和各寄存器 
** 输入参数: 无 
** 输出参数: 无 
********************************************************************************************************/ 
void InitCPU(void) 
{ 
    PORTB = 0x00; 
    DDRB = 0x08; 
    PORTC = 0x00; 
    DDRC = 0xC3; 
    PORTD = 0x10; 
    DDRD = 0xB0; 
 
    lcd_init();      // 液晶初始化 
    KEY_init();      // 按键初始化 
    pwm_init();      // PWM 初始化 
    s_analog_init(); // ADC 初始化 
    usart_init();    // 串口初始化 
} 
 
/********************************************************************************************************* 
** 函数名称: p10ms 
** 功能描述: 10 MS扫描程序 
** 输入参数: 无 
** 输出参数: 无 
********************************************************************************************************/ 
void p10ms(void) 
{ 
    //cell_output();    // 调用PWM输出控制程序 
} 
/********************************************************************************************************* 
** 函数名称: p100ms 
** 功能描述: 10 MS扫描程序 
** 输入参数: 无 
** 输出参数: 无 
********************************************************************************************************/ 
void p100ms(void) 
{ 
    static INT16U timecnt = 0; 
    INT8U i; 
    for(i=0; i<7; i++) 
    { 
        filter_adc(i); 
    } 
    if(timecnt % 2 == 0) 
    { 
        LED1 = !LED1; 
    } 
    ShowMenu();  // 显示菜单程序 
 
/* 
    lcd_locate(0,0); 
    lcd_print_number((((INT16U)Bat0_Vol_H << 8) + Bat0_Vol_L),4,0); 
    lcd_locate(0,1); 
    lcd_print_number((((INT16U)Bat0_Cur_H << 8) + Bat0_Cur_L),4,0); 
    lcd_locate(8,0); 
    lcd_print_number((((INT16U)Bat1_Vol_H << 8) + Bat1_Vol_L),4,0); 
    lcd_locate(8,1); 
    lcd_print_number((((INT16U)Bat1_Cur_H << 8) + Bat1_Cur_L),4,0); 
*/ 
    if(timecnt >= 60000) 
    { 
        timecnt = 0; 
    } 
    timecnt ++; 
} 
 
/********************************************************************************************************* 
** 函数名称: main 
** 功能描述: 主函数 
********************************************************************************************************/ 
void main(void) 
{ 
    // Declare local variables here 
    //INT16U i; 
    delay_ms(1000); // 上电延时 1 S ,保证 MCU 正常工作 
    InitCPU();      // 初始化 CPU 
    lcd_locate(0,0); 
    lcd_print_stringF("OurOUR, Charger "); 
    LED1 = 1; 
    LED2 = 1; 
    LED3 = 1; 
    LED4 = 1; 
    Enable();       // Global enable interrupts 
 
    delay_ms(200); 
    delay_ms(200); 
    delay_ms(200); 
    delay_ms(200); 
    delay_ms(200); 
 
/*    //第一次探测,探知电池是否就位 
    for(i=0; i<7; i++) 
    { 
        filter_adc(i); 
    } 
    //电池探测,是否有电池,根据电压探测 
    lcd_locate(0,0); 
    lcd_print_number(Memory_Char_to_Int(BAT_0_BASE + BAT_1_VOL - 1),4,0); 
    if(Memory_Char_to_Int(BAT_0_BASE+BAT_0_VOL-1)<4000) 
    lcd_print_stringF("BAT1 ready!"); 
    else 
    lcd_print_stringF("BAT1 empty!"); 
    lcd_locate(0,1); 
    if(Memory_Char_to_Int(BAT_1_BASE+BAT_1_VOL-1)<4000) 
    lcd_print_stringF("BAT0 ready!"); 
    else 
    lcd_print_stringF("BAT0 empty!"); 
 */ 
    delay_ms(200); 
    delay_ms(200); 
    delay_ms(200); 
    delay_ms(200); 
    delay_ms(200); 
 
    //bat_discharge(BAT0, 50); 
    while (1) 
    { 
        if(P10msReq) 
        { 
            P10msReq = 0; 
            p10ms();    // 处理 10 mS 函数 
        } 
        if (P100msReq) 
        { 
            P100msReq = 0; 
            p100ms();   // 处理 100 mS 函数 
        } 
  /* 
        if(memory[BAT0_PWM_VOL_OR_CUR-1]==VOL) 
	{ 
			lcd_locate(0,LINE_1); 
			lcd_print_stringF("Vol Control:"); 
			lcd_locate(0,LINE_2); 
			lcd_print_number(Memory_Char_to_Int(BAT0_VOL_SET-1),4,0); 
			lcd_locate(6,LINE_2); 
			lcd_print_number(Memory_Char_to_Int(BAT_0_BASE+BAT_0_VOL-1),4,0); 
	} 
        else 
	{ 
			lcd_locate(0,LINE_1); 
			lcd_print_stringF("Cur Control:"); 
			lcd_locate(0,LINE_2); 
			lcd_print_number(Memory_Char_to_Int(BAT0_CUR_SET-1),4,0); 
			lcd_locate(6,LINE_2); 
			lcd_print_number(Memory_Char_to_Int(BAT_0_BASE+BAT_0_CUR-1),4,0); 
			//lcd_print_number(cell_pid0(),4,0); 
		// 当调试放电的时候,最好监控OCR0的实际PWM参数 
		//	lcd_locate(0,LINE_2); 
		//	lcd_print_number(OCR0,3,0); 
	} 
 	delay_ms(200); 
	delay_ms(200); 
	delay_ms(200); 
	delay_ms(200); 
	delay_ms(200); 
	*/ 
    }; 
} 
/******************************************************************************************************** 
**                                 END OF FILE 
********************************************************************************************************/ 
/****************************************Copyright (c)************************************************** 
**                              智 能 充 电 器 开 发 小 组 
**                                     OurAVR 论坛 
**                                   QQ 群: 26052247 
** 
**                               http://www.ouravr.com/bbs 
** 
**--------------文件信息-------------------------------------------------------------------------------- 
**文   件   名: UART.c 
**创   建   人: 吕海安 
**最后修改日期: 2007年01月13日 
**描        述: UART的底层函数  FOR AVR MCU / Mega8 
** 
**--------------历史版本信息---------------------------------------------------------------------------- 
** 创建人: 吕海安 
** 版  本: v1.0 
** 日 期: 2007年07月13日 
** 描 述: 原始版本 
** 
**--------------当前版本修订------------------------------------------------------------------------------ 
** 修改人: 吕海安 
** 日 期: 2008年03月02日 
** 描 述: For 智能充电器  FOR AVR MCU / Mega16 
** 
**------------------------------------------------------------------------------------------------------ 
********************************************************************************************************/ 
#include "config.h" 
	#ifndef __SLEEP_DEFINED__ 
	#define __SLEEP_DEFINED__ 
	.EQU __se_bit=0x40 
	.EQU __sm_mask=0xB0 
	.EQU __sm_powerdown=0x20 
	.EQU __sm_powersave=0x30 
	.EQU __sm_standby=0xA0 
	.EQU __sm_ext_standby=0xB0 
	.EQU __sm_adc_noise_red=0x10 
	.SET power_ctrl_reg=mcucr 
	#endif 
#include "UART.h" 
#define RX_BUFFER_SIZE     8 
INT8S rx_buffer[RX_BUFFER_SIZE];   // USART Receiver buffer 
#if RX_BUFFER_SIZE < 256 
    INT8U rx_wr_index,rx_rd_index,rx_counter; 
#else 
    INT16U rx_wr_index,rx_rd_index,rx_counter; 
#endif 
bit rx_buffer_overflow;  // This flag is set on USART Receiver buffer overflow 
/********************************************************************************************************* 
** 函数名称: debug_usart_init 
** 功能描述: 串口通信初始化, 38400 
** 输入参数: 无 
** 输出参数: 无 
********************************************************************************************************/ 
void debug_usart_init(void) 
{ 
    UCSRB = 0x00; 
    UCSRA = 0x00; 
    UCSRC = BIT(URSEL) | 0x06; 
    UBRRL = 0x19; 
    UBRRH = 0x00; 
    UCSRB = 0x1C; 
} 
/********************************************************************************************************* 
** 函数名称: usart_init 
** 功能描述: 波特率 38400, 8位,发送中断模式,接收中断模式 
** 输入参数: 无 
** 输出参数: 无 
********************************************************************************************************/ 
void usart_init(void) 
{ 
    UCSRB = 0x00; 
    UCSRA = 0x00; 
    UCSRC = BIT(URSEL) | 0x06; 
    UBRRL = 0x19; 
    UBRRH = 0x00; 
    UCSRB = 0x9C; 
} 
/********************************************************************************************************* 
** 函数名称: usart_rx_isr 
** 功能描述: USART Receiver interrupt service routine 
** 输入参数: 无 
** 输出参数: 无 
********************************************************************************************************/ 
interrupt [USART_RXC] void usart_rx_isr(void) 
{ 
    INT8S status,data; 
    status = UCSRA; 
    data = UDR; 
    if ((status & (FRAMING_ERROR | PARITY_ERROR | DATA_OVERRUN)) == 0) 
    { 
        rx_buffer[rx_wr_index] = data; 
        if (++rx_wr_index == RX_BUFFER_SIZE) 
        { 
            rx_wr_index=0; 
        } 
        if (++rx_counter == RX_BUFFER_SIZE) 
        { 
            rx_counter = 0; 
            rx_buffer_overflow = 1; 
        }; 
    }; 
} 
/********************************************************************************************************* 
** 函数名称: getchar 
** 功能描述: Get a character from the USART Receiver buffer 
** 输入参数: 无 
** 输出参数: INT8S data: 串口接收缓存 
********************************************************************************************************/ 
#ifndef _DEBUG_TERMINAL_IO_ 
#define _ALTERNATE_GETCHAR_ 
#pragma used+ 
INT8S getchar(void) 
{ 
    INT8S data; 
    while (rx_counter == 0); 
    data = rx_buffer[rx_rd_index]; 
    if (++rx_rd_index == RX_BUFFER_SIZE) 
    { 
        rx_rd_index = 0; 
    } 
    Disable();     // 关中断 
    --rx_counter; 
    Enable();      // 开中断 
    return data; 
} 
#pragma used- 
#endif 
 
#define TX_BUFFER_SIZE 8 
INT8S tx_buffer[TX_BUFFER_SIZE];  // USART Transmitter buffer 
#if TX_BUFFER_SIZE<256 
    INT8U tx_wr_index,tx_rd_index,tx_counter; 
#else 
    INT16U tx_wr_index,tx_rd_index,tx_counter; 
#endif 
/********************************************************************************************************* 
** 函数名称: usart_tx_isr 
** 功能描述: USART Transmitter interrupt service routine 
** 输入参数: 无 
** 输出参数: 无 
********************************************************************************************************/ 
interrupt [USART_TXC] void usart_tx_isr(void) 
{ 
    if (tx_counter) 
    { 
        --tx_counter; 
        UDR = tx_buffer[tx_rd_index]; 
        if (++tx_rd_index == TX_BUFFER_SIZE) 
        { 
            tx_rd_index = 0; 
        } 
    }; 
} 
#ifndef _DEBUG_TERMINAL_IO_ 
#define _ALTERNATE_PUTCHAR_ 
#pragma used+ 
/********************************************************************************************************* 
** 函数名称: putchar 
** 功能描述: Write a character to the USART Transmitter buffer , 
**           发送采用查询方式 
** 输入参数: INT8S c: 要发送的字节 
** 输出参数: 无 
********************************************************************************************************/ 
void putchar(INT8S c) 
{ 
    while( !(UCSRA & (1<<UDRE)) ); 
    UDR = c; 
} 
/********************************************************************************************************* 
** 函数名称: putchar 
** 功能描述: Write a character to the USART Transmitter buffer , 
**           发送采用查询方式 
** 输入参数: INT8S c: 要发送的字节 
** 输出参数: 无 
********************************************************************************************************/ 
/* 
void putchar(INT8S c) 
{ 
    while (tx_counter == TX_BUFFER_SIZE); 
    Disable();     // 关中断 
    if (tx_counter || ((UCSRA & DATA_REGISTER_EMPTY)==0)) 
    { 
        tx_buffer[tx_wr_index] = c; 
        if (++tx_wr_index == TX_BUFFER_SIZE) 
        { 
            tx_wr_index = 0; 
        } 
        ++tx_counter; 
    } 
    else 
    { 
        UDR = c; 
    } 
    Enable();      // 开中断 
} 
*/ 
#pragma used- 
#endif 
 
/**************************************************************************************×***************** 
**                                 END OF FILE 
********************************************************************************************************/ 
/****************************************Copyright (c)************************************************** 
**                              智 能 充 电 器 开 发 小 组 
**                                     OurAVR 论坛 
**                                   QQ 群: 26052247 
** 
**                               http://www.ouravr.com/bbs 
** 
**--------------文件信息-------------------------------------------------------------------------------- 
**文   件   名: ADC.c 
**创   建   人: Trinove 
**最后修改日期: 2008年01月13日 
**描        述: AD转换的底层函数  FOR AVR MCU / Mega16 
** 
**--------------历史版本信息---------------------------------------------------------------------------- 
** 创建人: Trinove 
** 版  本: v0.03 
** 日 期: 2008年01月13日 
** 描 述: 原始版本 
** 
**--------------当前版本修订------------------------------------------------------------------------------ 
** 修改人: martin7wind 枫仔 
** 日 期: 2008年03月01日 
** 描 述: For 智能充电器 
** 
**--------------当前版本修订------------------------------------------------------------------------------ 
** 修改人: 吕海安 
** 日 期: 2008年03月02日 
** 描 述: 修改格式,归档 
**------------------------------------------------------------------------------------------------------ 
********************************************************************************************************/ 
#include "config.h" 
	#ifndef __SLEEP_DEFINED__ 
	#define __SLEEP_DEFINED__ 
	.EQU __se_bit=0x40 
	.EQU __sm_mask=0xB0 
	.EQU __sm_powerdown=0x20 
	.EQU __sm_powersave=0x30 
	.EQU __sm_standby=0xA0 
	.EQU __sm_ext_standby=0xB0 
	.EQU __sm_adc_noise_red=0x10 
	.SET power_ctrl_reg=mcucr 
	#endif 
#include "ADC.h" 
// ADCSR 
#define    ADEN     7 
#define    ADSC     6 
#define    ADATE    5 
#define    ADFR     5 
#define    ADIF     4 
#define    ADIE     3 
#define    ADPS2    2 
#define    ADPS1    1 
#define    ADPS0    0 
// 模拟量处理相关的全局变量的定义(仅在模块内被调用) 
 
/********************************************************************************************************* 
** 函数名称: s_analog_init 
** 功能描述: ADC 初始化,查询模式,预分频128,转换时间104us,右对齐 
** 输入参数: 无 
** 输出参数: 无 
********************************************************************************************************/ 
void s_analog_init(void) 
{ 
    // adc转换初始化 
    ADCSRA = 0x00;  // 禁止 AD 转换 
    ADMUX = 0x00; 
    SFIOR |= 0x00; 
    ACSR = 0x80;    // 禁止模拟比较器 
    ADCSRA = 0xE7; 
    //ADCSRA |= BIT(ADSC); 
} 
/********************************************************************************************************* 
** 函数名称: s_analog 
** 功能描述: 模拟量采集函数,用以一次采集某个关键模拟量 
** 输入参数: 无 
** 输出参数: INT16U result: ADC data 
********************************************************************************************************/ 
INT16U s_analog(void) 
{ 
    INT32U value = 0;  // 声明为long,否则在后续计算中会溢出 
    INT16U result = 0; 
    Disable(); 
    ADCSRA |= BIT(ADSC); // ADSR 置位,ADC开始 
    while(!(ADCSRA & BIT(ADIF))) // ADSR被清0代表转换完成 
    { 
        // 计算实际电压 
        value = ADCL; // 首先读低位 
        value |= (INT16S)ADCH << 8; // 然后读高位 
        result = (value * VREF_VOL) >> 10; // 10 Bit ADC 计算出采样到的电压值 
        Enable(); 
        break; 
    } 
    return result; 
} 
/********************************************************************************************************* 
** 函数名称: vol_to_bat_vol 
** 功能描述: ADC 测量电压向电池实际模拟量转化函数 
** 输入参数: INT16U vol: 电压采样电路上面 AD 采样出的值 
** 输出参数: INT16U result: 
********************************************************************************************************/ 
INT16U vol_to_bat_vol(INT16U vol) 
{ 
    INT16U temp = 0; 
    INT32U temp1 = 0; 
    temp1 = (vol * ((INT8U)(VOL_AMP * 10))) / 10; 
    temp = (INT16U) temp1; 
    return temp; 
} 
/********************************************************************************************************* 
** 函数名称: vol_to_bat_cur 
** 功能描述: 放电的时候,电压是负值 
**           采样电阻0.1欧. 
**           放电电流2A 
**           充电电流2A 
**           放大倍数为1+100/8.2=13.2 
**           放大后电压为0.1*2*13.2=+/-2.64 
**           放大器后偏置电压VREF=3.75 
**           最后的电压为1.11~6.39V 
**           最后的电压为(1.11~6.39V) / 2 = 0.555 V ~ 3.195 V 
** 
**           ( Vcur * 13.2 + 3.75 ) / 2 = Vadc 
**       =>   6.6 * Vcur = Vadc - 0x01FF / 2 
**       =>   CUR_AMP * Vcur = Vadc - 0xFF 
** 
** 输入参数: INT16U vol: 电流采样电路上面 AD 采样出的值 
** 输出参数: INT16S temp: 实际电流 mA 
********************************************************************************************************/ 
INT16S vol_to_bat_cur(INT16U vol) 
{ 
    INT32S temp; 
    temp = vol - (VREF_VOL / 2); 
    temp = (INT16S)(temp * 100 / (INT8U)(CUR_AMP * 10)); 
    return temp; 
} 
/********************************************************************************************************* 
** 函数名称: vol_to_temp 
** 功能描述: 
** 输入参数: INT16U vol: 
** 输出参数: INT16U vol: 
********************************************************************************************************/ 
INT16U vol_to_temp(INT16U vol) 
{ 
    return vol; 
} 
 
/********************************************************************************************************* 
** 函数名称: filter_adc 
** 功能描述: 多通道数值滤波处理,用全局变量做为缓冲区 
**           均值法滤波 
** 输入参数: INT8U channel: 
** 输出参数: 0 
********************************************************************************************************/ 
INT8U filter_adc(INT8U channel) 
{ 
    INT32U temp1 = 0; 
    INT16U result = 0; 
    ADMUX = (ADMUX & 0xF8) | channel;   // 选择对应的通道 
    delay_us(300); 
    s_analog();  // 舍去第一次值 
    result = s_analog(); 
 
    //将测量数据存入全局数据表 
    switch(channel) 
    { 
        case BAT_0_VOL_CH: 
            temp1 = (((INT16U)Bat0_Vol_H) << 8) + Bat0_Vol_L; 
            temp1 = temp1 * 0.75 + vol_to_bat_vol(result) * 0.25; 
            Bat0_Vol_H = (INT8U)(temp1 >> 8); 
            Bat0_Vol_L = (INT8U) (temp1 & 0xff); 
            break; 
        case BAT_0_CUR_CH: 
            if((result > (VREF_VOL / 2 - 100)) && (result < (VREF_VOL / 2 + 100))) 
            { 
                result = VREF_VOL / 2; 
            } 
            temp1 = ((INT16U)Bat0_Cur_H << 8) + Bat0_Cur_L; 
            temp1 = temp1 * 0.75 + vol_to_bat_cur(result) * 0.25; 
            Bat0_Cur_H = (INT8U)(temp1 >> 8); 
            Bat0_Cur_L = (INT8U) (temp1 & 0xff); 
          break; 
        case BAT_0_TEMP_CH: 
            temp1 = ((INT16U)Bat0_Temp_H << 8) + Bat0_Temp_L; 
            temp1 = temp1 * 0.75 + vol_to_temp(result) * 0.25; 
            Bat0_Temp_H = (INT8U)(temp1 >> 8); 
            Bat0_Temp_L = (INT8U) (temp1 & 0xff); 
            break; 
        case BAT_1_VOL_CH: 
            temp1 = (((INT16U)Bat1_Vol_H) << 8) + Bat1_Vol_L; 
            temp1 = temp1 * 0.75 + vol_to_bat_vol(result) * 0.25; 
            Bat1_Vol_H = (INT8U)(temp1 >> 8); 
            Bat1_Vol_L = (INT8U) (temp1 & 0xff); 
            break; 
        case BAT_1_CUR_CH: 
            if((result > (VREF_VOL / 2 - 100)) && (result < (VREF_VOL / 2 + 100))) 
            { 
                result = VREF_VOL / 2; 
            } 
            temp1 = ((INT16U)Bat1_Cur_H << 8) + Bat1_Cur_L; 
            temp1 = temp1 * 0.75 + vol_to_bat_cur(result) * 0.25; 
            Bat1_Cur_H = (INT8U)(temp1 >> 8); 
            Bat1_Cur_L = (INT8U) (temp1 & 0xff); 
            break; 
        case BAT_1_TEMP_CH: 
            temp1 = ((INT16U)Bat1_Temp_H << 8) + Bat1_Temp_L; 
            temp1 = temp1 * 0.75 + vol_to_temp(result) * 0.25; 
            Bat1_Temp_H = (INT8U)(temp1 >> 8); 
            Bat1_Temp_L = (INT8U) (temp1 & 0xff); 
            break; 
        default: 
            break;     // 异常处理为空 
    } 
    return 0; 
} 
/********************************************************************************************************* 
** 函数名称: ReadBatterySTAT 
** 功能描述: 察看电池状态 
** 输入参数: INT8U channel: 第几路电池 
** 输出参数: 0 
********************************************************************************************************/ 
void ReadBatterySTAT(INT8U channel) 
{ 
    INT8U Key = NO_KEY; 
    INT8U i; 
    if(channel == BATTERY0) 
    { 
        lcd_locate(0,0); 
        lcd_print_stringF("BAT0:       mV  "); 
        lcd_locate(0,1); 
        lcd_print_stringF("            mA  "); 
    } 
    else if (channel == BATTERY1) 
    { 
        lcd_locate(0,0); 
        lcd_print_stringF("BAT1:       mV  "); 
        lcd_locate(0,1); 
        lcd_print_stringF("            mA  "); 
    } 
    else if (channel == BATTERY_BOTH) 
    { 
        lcd_cls();  // 清屏 
        lcd_locate(5,0); 
        lcd_print_stringF("mV"); 
         lcd_locate(14,0); 
        lcd_print_stringF("mV"); 
        lcd_locate(5,1); 
        lcd_print_stringF("mA"); 
         lcd_locate(14,1); 
        lcd_print_stringF("mA"); 
    } 
    while (Key != BT_CANCEL) 
    { 
        LED1 = 1; 
        LED2 = !LED2; 
        for(i=0; i<7; i++) 
        { 
            filter_adc(i); 
        } 
        if(channel == BATTERY0) 
        { 
            lcd_locate(7,0); 
            lcd_print_number((((INT16U)Bat0_Vol_H << 8) + Bat0_Vol_L),4,0); 
            lcd_locate(7,1); 
            lcd_print_number((((INT16U)Bat0_Cur_H << 8) + Bat0_Cur_L),4,0); 
        } 
        else if (channel == BATTERY1) 
        { 
            lcd_locate(7,0); 
            lcd_print_number((((INT16U)Bat1_Vol_H << 8) + Bat1_Vol_L),4,0); 
            lcd_locate(7,1); 
            lcd_print_number((((INT16U)Bat1_Cur_H << 8) + Bat1_Cur_L),4,0); 
        } 
        else if (channel == BATTERY_BOTH) 
        { 
            lcd_locate(0,0); 
            lcd_print_number((((INT16U)Bat0_Vol_H << 8) + Bat0_Vol_L),4,0); 
            lcd_locate(0,1); 
            lcd_print_number((((INT16U)Bat0_Cur_H << 8) + Bat0_Cur_L),4,0); 
            lcd_locate(9,0); 
            lcd_print_number((((INT16U)Bat1_Vol_H << 8) + Bat1_Vol_L),4,0); 
            lcd_locate(9,1); 
            lcd_print_number((((INT16U)Bat1_Cur_H << 8) + Bat1_Cur_L),4,0); 
        } 
        Key = read_keycode(); 
    } 
} 
/**************************************************************************************×***************** 
**                                 END OF FILE 
********************************************************************************************************/ 
/****************************************Copyright (c)************************************************** 
**                              智 能 充 电 器 开 发 小 组 
**                                     OurAVR 论坛 
**                                   QQ 群: 26052247 
** 
**                               http://www.ouravr.com/bbs 
** 
**--------------文件信息-------------------------------------------------------------------------------- 
**文   件   名: LCD1206.c 
**创   建   人: Trinove 
**最后修改日期: 2008年01月13日 
**描        述: LCD1602字符型液晶的底层函数  FOR AVR MCU / Mega16 
** 
**--------------历史版本信息---------------------------------------------------------------------------- 
** 创建人: 吕海安 
** 版  本: v1.0 
** 日 期: 2008年01月13日 
** 描 述: 原始版本 
** 
**--------------历史版本信息------------------------------------------------------------------------------ 
** 修改人: martin7wind 
** 日 期: 2008年02月03日 
** 描 述: For 智能充电器 
** 
**--------------当前版本修订------------------------------------------------------------------------------ 
** 修改人: 吕海安 
** 日 期: 2008年03月02日 
** 描 述: 修改格式,归档 
** 
**------------------------------------------------------------------------------------------------------ 
**--------------当前版本修订------------------------------------------------------------------------------ 
** 修改人: 村长 aleyn.wu 
** 日 期: 2008年3月3日 
** 描 述: 修改了一些BUG,使本项目能在CVAVR下编译通过 
**         增加了一个函数 
**------------------------------------------------------------------------------------------------------ 
********************************************************************************************************/ 
#include "config.h" 
	#ifndef __SLEEP_DEFINED__ 
	#define __SLEEP_DEFINED__ 
	.EQU __se_bit=0x40 
	.EQU __sm_mask=0xB0 
	.EQU __sm_powerdown=0x20 
	.EQU __sm_powersave=0x30 
	.EQU __sm_standby=0xA0 
	.EQU __sm_ext_standby=0xB0 
	.EQU __sm_adc_noise_red=0x10 
	.SET power_ctrl_reg=mcucr 
	#endif 
#include "LCD1602.h" 
 
/*---------------------------------------------------------------------------- 
四线模式: 
LCD: 1602 
PIN0~7, RW, E, RS 
连线如下: 
PIN7 --> PB4 
PIN6 --> PD2 
PIN5 --> PD3 
PIN4 --> PD6 
RW   --> GND (R/W = 0 write) 
E    --> PA6 (E = 1 enable ) 
RS   --> PA7 (RS = 0 CMD; RS = 1 DATA ) 
---------------------------------------------------------------------------*/ 
#define LCD_DATA7_DDR    DDRB 
#define LCD_DATA6_DDR    DDRD 
#define LCD_DATA5_DDR    DDRD 
#define LCD_DATA4_DDR    DDRD 
#define LCD_DATA7_PIN    PINB 
#define LCD_DATA6_PIN    PIND 
#define LCD_DATA5_PIN    PIND 
#define LCD_DATA4_PIN    PIND 
#define LCD_DATA7_PORT   PORTB 
#define LCD_DATA6_PORT   PORTD 
#define LCD_DATA5_PORT   PORTD 
#define LCD_DATA4_PORT   PORTD 
#define LCD_DATA7 PB4 
#define LCD_DATA6 PD2 
#define LCD_DATA5 PD3 
#define LCD_DATA4 PD6 
#define LCD_E_DDR        DDRA 
#define LCD_E_PORT       PORTA 
#define LCD_E            PA6 
#define LCD_E_HIGH       BIT_SET(LCD_E_PORT, LCD_E) 
#define LCD_E_LOW        BIT_CLR(LCD_E_PORT, LCD_E) 
#define LCD_RS_DDR       DDRA 
#define LCD_RS_PORT      PORTA 
#define LCD_RS           PA7 
#define LCD_DATA_MODE    BIT_SET(LCD_RS_PORT, LCD_RS) 
#define LCD_CMD_MODE     BIT_CLR(LCD_RS_PORT, LCD_RS) 
 
#define BIT_POSITION7    (1<<7) 
#define BIT_POSITION6    (1<<6) 
#define BIT_POSITION5    (1<<5) 
#define BIT_POSITION4    (1<<4) 
#define LINE_1 0 
#define LINE_2 1 
INT16U temp; 
/******************************************************************************************************* 
** 函数名称: delay_1us 
** 功能描述: delay 1 us,16mhz, 1 nop bring 62.5ns delay 
** 输入参数: 无 
** 输出参数: 无 
********************************************************************************************************/ 
void delay_1us(void) 
{ 
    INT8U i; 
    for(i = 15; i > 0; i--); 
} 
/******************************************************************************************************* 
** 函数名称: delay_xus 
** 功能描述: 延时 N uS 
** 输入参数: INT8U t: N 个单位 
** 输出参数: 无 
********************************************************************************************************/ 
void delay_xus(INT8U t) 
{ 
    for( ; t>0; t--) 
    { 
        delay_1us(); 
    } 
} 
/******************************************************************************************************* 
** 函数名称: lcd_write_cmd 
** 功能描述: 最初的初始化设置中,写入数据函数 
** 输入参数: INT8U cmd: 命令 
** 输出参数: 无 
********************************************************************************************************/ 
void lcd_write_cmd(INT8U cmd) 
{ 
    LCD_CMD_MODE; 
    if(cmd & BIT_POSITION7) 
        {BIT_SET(LCD_DATA7_PORT, LCD_DATA7);} 
    else 
        {BIT_CLR(LCD_DATA7_PORT, LCD_DATA7);} 
    if(cmd & BIT_POSITION6) 
        {BIT_SET(LCD_DATA6_PORT, LCD_DATA6);} 
    else 
        {BIT_CLR(LCD_DATA6_PORT, LCD_DATA6);} 
    if(cmd & BIT_POSITION5) 
        {BIT_SET(LCD_DATA5_PORT, LCD_DATA5);} 
    else 
        {BIT_CLR(LCD_DATA5_PORT, LCD_DATA5);} 
    if(cmd & BIT_POSITION4) 
        {BIT_SET(LCD_DATA4_PORT, LCD_DATA4);} 
    else 
        {BIT_CLR(LCD_DATA4_PORT, LCD_DATA4);} 
 
    LCD_E_HIGH;     // E 信号 
    delay_us(5); 
    LCD_E_LOW; 
} 
/******************************************************************************************************* 
** 函数名称: lcd_write_byte 
** 功能描述: 向LCD写入数据 
** 输入参数: INT8U byte: 数据 
**           INT8U type: 类型 
** 输出参数: 无 
********************************************************************************************************/ 
void lcd_write_byte(INT8U byte, INT8U type) 
{ 
    if(type) 
    	{LCD_DATA_MODE;} 
    else 
    	{LCD_CMD_MODE;} 
 
    temp = byte; 
 
    if(byte & BIT_POSITION7) 
        {BIT_SET(LCD_DATA7_PORT, LCD_DATA7);} 
    else 
        {BIT_CLR(LCD_DATA7_PORT, LCD_DATA7);} 
    if(byte&BIT_POSITION6) 
        {BIT_SET(LCD_DATA6_PORT, LCD_DATA6);} 
    else 
        {BIT_CLR(LCD_DATA6_PORT, LCD_DATA6);} 
    if(byte&BIT_POSITION5) 
        {BIT_SET(LCD_DATA5_PORT, LCD_DATA5);} 
    else 
        {BIT_CLR(LCD_DATA5_PORT, LCD_DATA5);} 
    if(byte&BIT_POSITION4) 
        {BIT_SET(LCD_DATA4_PORT, LCD_DATA4);} 
    else 
        {BIT_CLR(LCD_DATA4_PORT, LCD_DATA4);} 
 
    LCD_E_HIGH;    // E 信号 
    delay_us(5); 
    LCD_E_LOW; 
    delay_xus(39); // 39 us! 
    byte <<= 4; 
    if(byte & BIT_POSITION7) 
        {BIT_SET(LCD_DATA7_PORT, LCD_DATA7);} 
    else 
        {BIT_CLR(LCD_DATA7_PORT, LCD_DATA7);} 
    if(byte & BIT_POSITION6) 
        {BIT_SET(LCD_DATA6_PORT, LCD_DATA6);} 
    else 
        {BIT_CLR(LCD_DATA6_PORT, LCD_DATA6);} 
    if(byte & BIT_POSITION5) 
        {BIT_SET(LCD_DATA5_PORT, LCD_DATA5);} 
    else 
        {BIT_CLR(LCD_DATA5_PORT, LCD_DATA5);} 
    if(byte & BIT_POSITION4) 
        {BIT_SET(LCD_DATA4_PORT, LCD_DATA4);} 
    else 
        {BIT_CLR(LCD_DATA4_PORT, LCD_DATA4);} 
 
    LCD_E_HIGH;     // E 信号 
    delay_xus(5); 
    LCD_E_LOW; 
    delay_ms(10);  // 延时 10 mS 
} 
 
/******************************************************************************************************* 
** 函数名称: lcd_cls 
** 功能描述: 清屏 
** 输入参数: 无 
** 输出参数: 无 
********************************************************************************************************/ 
void lcd_cls() 
{ 
    lcd_write_byte(0x01, CMD); 
} 
/******************************************************************************************************* 
** 函数名称: lcd_init 
** 功能描述: 1602 液晶初始化函数 
** 输入参数: 无 
** 输出参数: 无 
********************************************************************************************************/ 
void lcd_init() 
{ 
    // 相关IO配置 
    BIT_SET(LCD_DATA7_DDR, LCD_DATA7); 
    BIT_SET(LCD_DATA6_DDR, LCD_DATA6); 
    BIT_SET(LCD_DATA5_DDR, LCD_DATA5); 
    BIT_SET(LCD_DATA4_DDR, LCD_DATA4); 
    BIT_SET(LCD_E_DDR, LCD_E); 
    BIT_SET(LCD_RS_DDR, LCD_RS); 
    delay_ms(15);          // 上电延时15MS以上 
    lcd_write_cmd(0x30);    // 上电初始化命令 
    delay_ms(5);           // delay > 5.1MS 
    lcd_write_cmd(0x30); 
    delay_ms(5);           // delay > 100us 
    lcd_write_cmd(0x30); 
    delay_ms(15); 
    lcd_write_cmd(0x20);    // 四位数据模式 
    delay_ms(15); 
    //功能设定 
    lcd_write_byte(0x28, CMD);   // 0x28 = 4 位数据线,双行显示,5*7 字型 
    //LCD_write_byte(0x0e, CMD); // 0x0e = 显示开,光标不闪烁 
    lcd_write_byte(0x0c, CMD);   // 0x0c = 显示开,光标不显示 
    lcd_write_byte(0x06, CMD);   // 0x06 = 每次输入后光标右移一格 
    lcd_cls();  // 清屏 
} 
/******************************************************************************************************* 
** 函数名称: lcd_write_char 
** 功能描述: 在 X,Y 坐标写单字符 
** 输入参数: INT8U lcd_x: x 坐标 
**           INT8U lcd_y: y 坐标 
**           INT8U data:  单字符 
** 输出参数: 无 
********************************************************************************************************/ 
void lcd_write_char(INT8U lcd_x, INT8U lcd_y, INT8U data) 
{ 
    if(lcd_y) // 第二行 
    { 
        lcd_write_byte(0xc0+lcd_x, CMD); 
    } 
    else      // 第一行 
    { 
        lcd_write_byte(0x80+lcd_x, CMD); 
    } 
    lcd_write_byte(data, DATA); 
} 
 
/******************************************************************************************************* 
** 函数名称: lcd_locate 
** 功能描述: 定位 LCD 行列位置 
** 输入参数: INT8U lcd_x: x 坐标 
**           INT8U lcd_y: y 坐标 
** 输出参数: 无 
********************************************************************************************************/ 
void lcd_locate(INT8U lcd_x, INT8U lcd_y) 
{ 
    if(lcd_y) // 第二行 
    { 
        lcd_write_byte(0xc0 + lcd_x, CMD); 
    } 
    else      // 第一行 
    { 
        lcd_write_byte(0x80 + lcd_x, CMD); 
    } 
} 
 
/******************************************************************************************************* 
** 函数名称: lcd_print_string 
** 功能描述: 向 LCD 发送显示文字 
** 输入参数: char *pstring: 显示文字指针pstring 
** 输出参数: 无 
********************************************************************************************************/ 
void lcd_print_string(char *pstring) 
{ 
    while(*pstring) 
    { 
        lcd_write_byte(*pstring, DATA); 
        pstring++; 
    } 
} 
/******************************************************************************************************* 
** 函数名称: lcd_print_stringF 
** 功能描述: 向 LCD 发送显示文字 
** 输入参数: flash char *pstring: 显示文字指针pstring 
** 输出参数: 无 
********************************************************************************************************/ 
void lcd_print_stringF(flash char *pstring) 
{ 
    while(*pstring) 
    { 
        lcd_write_byte(*pstring, DATA); 
        pstring++; 
    } 
} 
/******************************************************************************************************* 
** 函数名称: lcd_print_number 
** 功能描述: 向 LCD 发送显示数据 
** 输入参数: INT16S number: 数值, 为有符号的整数 
**           INT8U ca: 显示的位数 (1 - 6) 
**           INT8U cb: 其中的小数位数,(类似定点的小数),显示整数时,cb 置 0 即可 
** 输出参数: 无 
********************************************************************************************************/ 
void lcd_print_number(INT16S number , INT8U ca , INT8U cb) 
{ 
    INT8U _bit[5];   // 最多 5 位 
    INT8U *pbit; 
    INT8U i; 
    if(number > 0) 
    { 
        temp = number; 
    } 
    else 
    { 
        temp = -number; 
    } 
    // temp = 12345; 
    // 算出每一位 057920 
    _bit[4] = (INT8U)(temp/10000); 
    _bit[3] = (INT8U)(temp/1000  - _bit[4]*10); 
    _bit[2] = (INT8U)(temp/100  - _bit[4]*100 - _bit[3]*10); 
    _bit[1] = (INT8U)(temp/10  - _bit[4]*1000 - _bit[3]*100 - _bit[2]*10); 
    _bit[0] = (INT8U)(temp  - _bit[4]*10000 - _bit[3]*1000 - _bit[2]*100 - _bit[1]*10); 
    if(number < 0) // 负值 
    { 
        lcd_write_byte('-', DATA);	//先显示负号 
        pbit = &(_bit [4]);   //指向最高位 
        for(i = 5 - ca; i > 0; i--) 
        { 
            pbit --; 
        } 
        while(ca) 
        { 
            if(ca == cb) 
            { 
                lcd_write_byte('.', DATA); 
            } 
            lcd_write_byte(*pbit+48, DATA); 
            pbit --; 
            ca--; 
        } 
    } 
    else  // 正数 
    { 
    	pbit = &(_bit [4]);   //指向最高位 
    	for(i = 5 - ca; i > 0; i--) 
    	{ 
            pbit --; 
        } 
    	while(ca) 
        { 
            if(ca == cb) 
            { 
                lcd_write_byte('.', DATA); 
            } 
            lcd_write_byte(*pbit+48,DATA); 
            pbit --; 
            ca--; 
        } 
    } 
} 
 
/**************************************************************************************×***************** 
**                                 END OF FILE 
********************************************************************************************************/ 
/****************************************Copyright (c)************************************************** 
**                              智 能 充 电 器 开 发 小 组 
**                                     OurAVR 论坛 
**                                   QQ 群: 26052247 
** 
**                               http://www.ouravr.com/bbs 
** 
**--------------文件信息-------------------------------------------------------------------------------- 
**文   件   名: PWM.c 
**创   建   人: Trinove 
**最后修改日期: 2008年01月13日 
**描        述: PWM 输出的底层函数  FOR AVR MCU / Mega16 
** 
**--------------历史版本信息---------------------------------------------------------------------------- 
** 创建人: Trinove 
** 版  本: v0.01 
** 日 期: 2008年01月13日 
** 描 述: 原始版本 
** 
**--------------历史版本信息------------------------------------------------------------------------------ 
** 修改人: martin7wind 
** 日 期: 2008年02月24日 
** 描 述: For 智能充电器 
** 
**--------------当前版本修订------------------------------------------------------------------------------ 
** 修改人: 吕海安 
** 日 期: 2008年03月03日 
** 描 述: 修改格式,归档 
** 
**------------------------------------------------------------------------------------------------------ 
**--------------当前版本修订------------------------------------------------------------------------------ 
** 修改人: 村长 aleyn.wu 
** 日 期: 2008年3月3日 
** 描 述: 修改了一些BUG,使本项目能在CVAVR下编译通过 
** 
**------------------------------------------------------------------------------------------------------ 
********************************************************************************************************/ 
#include "config.h" 
	#ifndef __SLEEP_DEFINED__ 
	#define __SLEEP_DEFINED__ 
	.EQU __se_bit=0x40 
	.EQU __sm_mask=0xB0 
	.EQU __sm_powerdown=0x20 
	.EQU __sm_powersave=0x30 
	.EQU __sm_standby=0xA0 
	.EQU __sm_ext_standby=0xB0 
	.EQU __sm_adc_noise_red=0x10 
	.SET power_ctrl_reg=mcucr 
	#endif 
#include "PWM.h" 
 
#define CHARGER_CHANNEL_1_OCR   OCR1A 
#define CHARGER_CHANNEL_2_OCR   OCR1B 
 
// 根据全局数据表的PWM相关定义 
#define PID_FLAG     18 
#define CHARGE       1 
#define DisCHARGE    2 
// 打开或关闭 Timer1 
#define START_CHARGE	     TCCR1B = 0x0A 
#define STOP_CHARGE	     TCCR1B = 0x00 
// 更改端口的输入输出特性,从而控制放电 
#define STOP_DisCHARGE	     BIT_CLR(DDRB, PB3);BIT_CLR(DDRD,PD7) 
#define START_DisCHARGE      BIT_SET(DDRB, PB3);BIT_SET(DDRD,PD7) 
//BAT0 
#define BAT0_PWM_STATUS             40 
#define BAT0_PWM_VOL_OR_CUR         41  // 0: vol, 1: cur 
#define BAT0_PWM_OUTPUT_STATUS      42  // 0: 连续, 1: 断续 
#define BAT0_PWM_BAT0               43 
#define BAT0_PID_P                  45 
#define BAT0_PID_I                  47 
#define BAT0_PID_D                  49 
#define BAT0_VOL_SET                51 
#define BAT0_CUR_SET                53 
#define BAT0_PCHARGE_CHARGE_TIME    55 
#define BAT0_PCHARGE_DiCHARGE_TIME  56 
#define BAT0_PCHARGE_PAUSE_TIME     57 
//BAT1 
#define BAT1_PWM_STATUS             61 
#define BAT1_PWM_VOL_OR_CUR         62  // 0: vol, 1: cur 
#define BAT1_PWM_OUTPUT_STATUS      63  // 0: 连续, 1: 断续 
#define BAT1_PWM_BAT1               64 
#define BAT1_PID_P                  66 
#define BAT1_PID_I                  68 
#define BAT1_PID_D                  70 
#define BAT1_VOL_SET                73 
#define BAT1_CUR_SET                75 
#define BAT1_PCHARGE_CHARGE_TIME    76 
#define BAT1_PCHARGE_DiCHARGE_TIME  77 
#define BAT1_PCHARGE_PAUSE_TIME     78 
#define VOL 1 
#define CUR 2 
 
/******************************************************************************************************* 
** 函数名称: pwm_port_init 
** 功能描述: PWM 输出端口定义初始化 
** 输入参数: 无 
** 输出参数: 无 
********************************************************************************************************/ 
void pwm_port_init() 
{ 
    BIT_SET(DDRD, PD5); 
    BIT_SET(DDRD, PD4); 
    BIT_SET(DDRB,PB3); 
    BIT_SET(DDRD,PD7); 
} 
/******************************************************************************************************* 
** 函数名称: timer0_init 
** 功能描述: 定时器 T0 初始化 
** 输入参数: 无 
** 输出参数: 无 
********************************************************************************************************/ 
void timer0_init(void) 
{ 
    // Timer/Counter 0 initialization 
    // Clock source: System Clock 
    // Clock value: 15.625 kHz 
    // Mode: Fast PWM top=FFh 
    // OC0 output: Non-Inverted PWM 
    TCCR0  = 0x00;  // 停止定时器 
    TCNT0  = 0x00;  // 初始值   16.384 mS 
    OCR0   = 0x00;  // 匹配值 
    TIMSK |= 0x01;  // 中断允许 
    //TCCR0  = 0x6D;  // 启动定时器 
    TCCR0  = 0x4D;  // 启动定时器 
} 
/******************************************************************************************************* 
** 函数名称: timer0_init 
** 功能描述: 定时 T1 初始化 
**           OCR1A 升序匹配0,降序匹配1 
**           OCR1B 升序匹配0,降序匹配1 
**           8 的预分频,3.906KHZ 
**           9 位快速PWM 
** 输入参数: 无 
** 输出参数: 无 
********************************************************************************************************/ 
void timer1_init(void) 
{ 
// Timer/Counter 1 initialization 
// Clock source: System Clock 
// Clock value: 16000.000 kHz 
// Mode: Fast PWM top=01FFh 
// OC1A output: Non-Inv. 
// OC1B output: Non-Inv. 
// Noise Canceler: Off 
// Input Capture on Falling Edge 
// Timer 1 Overflow Interrupt: Off 
// Input Capture Interrupt: Off 
// Compare A Match Interrupt: Off 
// Compare B Match Interrupt: Off 
    TCCR1B = 0x00;  // 停止定时器 
    TIMSK |= 0x00;  // 中断允许 
    TCNT1H = 0x00; 
    TCNT1L = 0x00;  // 初始值 
    OCR1AH = 0x00; 
    OCR1AL = 0x00;  // 匹配 A 值 
    OCR1BH = 0x00; 
    OCR1BL = 0x7F;  // 匹配 B 值 
    ICR1H  = 0xFF; 
    ICR1L  = 0xFF;  // 输入捕捉匹配值 
    TCCR1A = 0xA2; 
    TCCR1B = 0x09;  // 启动定时器 
} 
 
/******************************************************************************************************* 
** 函数名称: timer0_init 
** 功能描述: 定时器 T2 初始化 
** 输入参数: 无 
** 输出参数: 无 
********************************************************************************************************/ 
void timer2_init(void) 
{ 
    // Timer/Counter 2 initialization 
    // Clock source: System Clock 
    // Clock value: 15.625 kHz 
    // Mode: Fast PWM top=FFh 
    // OC2 output: Non-Inverted PWM 
    TCCR2  = 0x00;  // 停止定时器 
    ASSR   = 0x00;  // 异步时钟模式 
    TCNT2  = 0x00;  // 初始值 
    OCR2   = 0x7f;  // 匹配值 
    TIMSK |= 0x00;  // 中断不允许 
    //TCCR2  = 0x6F;  // 启动定时器 
    TCCR2 = 0x4F; 
} 
/******************************************************************************************************* 
** 函数名称: pwm_init 
** 功能描述: PWM 初始化 
** 输入参数: 无 
** 输出参数: 无 
********************************************************************************************************/ 
void pwm_init() 
{ 
    pwm_port_init(); // 端口初始化 
    timer1_init();   // 两路充电 PWM 
    timer0_init();   // 第一路放电 PWM,主时钟 
    timer2_init();   // 第二路放电 PWM 
} 
#define BAT0   1 
#define BAT1   2 
/******************************************************************************************************* 
** 函数名称: bat_discharge 
** 功能描述: 电池放电, 仅支持电流模式 
** 输入参数: INT8U bat_no: 
**           INT16U discharge_value: 
** 输出参数: 无 
********************************************************************************************************/ 
void bat_discharge(INT8U bat_no,INT16U discharge_value) 
{ 
/*    STOP_CHARGE;    // 关闭充电 
    START_DisCHARGE;    // 开始放电 
    if(bat_no == BAT0) 
    { 
        memory[BAT0_PWM_STATUS - 1] = DisCHARGE; 
        memory[BAT0_CUR_SET - 1] = discharge_value >> 8; 
        memory[BAT0_CUR_SET] = discharge_value & 0x00ff; 
    } 
    else 
    { 
        memory[BAT1_PWM_STATUS - 1] = DisCHARGE; 
        memory[BAT1_CUR_SET - 1] = discharge_value >> 8; 
        memory[BAT1_CUR_SET] = discharge_value & 0x00ff; 
    } 
*/ 
} 
/******************************************************************************************************* 
** 函数名称: bat_charge_set 
** 功能描述: 电池充电设置 
** 输入参数: INT8U bat_no: 电池 1 或 2 
**           INT8U cur_or_vol: 电流控制还是电压控制 
**           INT16U charge_data_set: 电流或电压设置值 
** 输出参数: 无 
********************************************************************************************************/ 
void bat_charge_set(INT8U bat_no, INT8U cur_or_vol,INT16U charge_data_set) 
{ 
/*    //关闭放电 
    STOP_DisCHARGE; 
    START_CHARGE; 
    if(bat_no == BAT0) 
    { 
        memory[BAT0_PWM_STATUS - 1] = CHARGE; 
        memory[BAT0_PWM_VOL_OR_CUR - 1] = cur_or_vol; 
        if(cur_or_vol==VOL) 
        { 
            memory[BAT0_VOL_SET - 1] = charge_data_set >> 8; 
            memory[BAT0_VOL_SET] = charge_data_set & 0x00ff; 
        } 
        else if(cur_or_vol==CUR) 
        { 
            memory[BAT0_CUR_SET - 1] = charge_data_set >> 8; 
            memory[BAT0_CUR_SET] = charge_data_set & 0x00ff; 
        } 
        else 
        { 
        } 
    } 
    else if(bat_no == BAT1) 
    { 
        memory[BAT1_PWM_STATUS - 1] = CHARGE; 
        memory[BAT1_PWM_VOL_OR_CUR - 1] = cur_or_vol; 
        if(cur_or_vol == VOL) 
        { 
            memory[BAT1_VOL_SET - 1] = charge_data_set >> 8; 
            memory[BAT1_VOL_SET] = charge_data_set & 0x00ff; 
        } 
        else if(cur_or_vol == CUR) 
        { 
            memory[BAT1_CUR_SET - 1] = charge_data_set >> 8; 
            memory[BAT1_CUR_SET] = charge_data_set & 0x00ff; 
        } 
        else 
        { 
        // 
        } 
    }*/ 
} 
/******************************************************************************************************* 
** 函数名称: cell_pid0 
** 功能描述: 电池1 PID 运算 
** 输入参数: 无 
** 输出参数: PID运算出来的差值 
********************************************************************************************************/ 
INT16S cell_pid0(void) 
{ 
    INT16S result; 
  /* 
    if(memory[BAT0_PWM_STATUS - 1] == CHARGE) 
    { 
        if(memory[BAT0_PWM_VOL_OR_CUR-1] == VOL) 
        { 
            filter_adc(BAT_0_VOL_CH); 
            result = Memory_Char_to_Int(BAT_0_BASE + BAT_0_VOL - 1) - Memory_Char_to_Int(BAT0_VOL_SET - 1); 
        } 
        else if(memory[BAT0_PWM_VOL_OR_CUR - 1] == CUR) 
        { 
            filter_adc(BAT_0_CUR_CH); 
            result = Memory_Char_to_Int(BAT_0_BASE + BAT_0_CUR - 1) - Memory_Char_to_Int(BAT0_CUR_SET - 1); 
        } 
        else 
        { 
        } 
    } 
    else if(memory[BAT0_PWM_STATUS - 1] == DisCHARGE) 
    { 
        filter_adc(BAT_0_CUR_CH); 
        result = Memory_Char_to_Int(BAT_0_BASE + BAT_0_CUR - 1) + Memory_Char_to_Int(BAT0_CUR_SET - 1); 
    } 
    else 
    { 
        //put_c(98); 
    } 
                  */ 
    return result; 
} 
 
/******************************************************************************************************* 
** 函数名称: cell_pid1 
** 功能描述: 电池2 PID 运算 
** 输入参数: 无 
** 输出参数: PID运算出来的差值 
********************************************************************************************************/ 
INT16S cell_pid1(void) 
{ 
    INT16S result; 
    return result; 
} 
 
/******************************************************************************************************* 
** 函数名称: cell_output 
** 功能描述: 电池1、2  PWM  输出控制 
**           根据需要调用相应的PID控制程序,由PID使能标志控制 
** 输入参数: 无 
** 输出参数: 无 
********************************************************************************************************/ 
void cell_output(void) 
{   /* 
    INT16U pwm_value; 
    INT8U temp; 
    temp = OCR1AH; 
    pwm_value = ((INT16U)temp) << 8; 
    pwm_value |= OCR1AL; 
    if(memory[18])  //进行PID运算控制PWM 
    { 
    } 
    else  //直接进行PWM控制操作 
    { 
        if(cell_pid0() > 0) 
        { 
            //put_c(98); 
            if(memory[BAT0_PWM_STATUS - 1] == CHARGE) 
            { 
                //put_c(97); 
                if(pwm_value != 0x0000) 
                { 
                    pwm_value--; 
                } 
                OCR1AH = (INT8U)(pwm_value >> 8); 
                OCR1AL = (INT8U)(pwm_value & 0x00ff); 
            } 
            else if(memory[BAT0_PWM_STATUS - 1] == DisCHARGE) 
            { 
                if(OCR0 != 0xfe) 
                { 
                    OCR0 ++; 
                } 
            } 
        } 
        else 
        { 
            //put_c(97); 
            if(memory[BAT0_PWM_STATUS - 1] == CHARGE) 
            { 
                if(pwm_value != 0xFFFF) 
                pwm_value++; 
                OCR1AH = (INT8U)(pwm_value >> 8); 
                OCR1AL = (INT8U)(pwm_value & 0x00ff); 
            } 
            else if(memory[BAT0_PWM_STATUS - 1] == DisCHARGE) 
            { 
                if(OCR2 != 0x01) 
                { 
                    OCR0 --; 
                } 
            } 
        } 
    }*/ 
} 
/**************************************************************************************×***************** 
**                                 END OF FILE 
********************************************************************************************************/ 
/****************************************Copyright (c)************************************************** 
**                              智 能 充 电 器 开 发 小 组 
**                                     OurAVR 论坛 
**                                   QQ 群: 26052247 
** 
**                               http://www.ouravr.com/bbs 
** 
**--------------文件信息-------------------------------------------------------------------------------- 
**文   件   名: SIO.c 
**创   建   人: Trinove 
**最后修改日期: 2008年01月13日 
**描        述: 按键的底层函数  FOR AVR MCU / Mega16 
** 
**--------------历史版本信息---------------------------------------------------------------------------- 
** 创建人: Trinove 
** 版  本: v0.01 
** 日 期: 2008年01月13日 
** 描 述: 原始版本 
** 
**--------------当前版本修订------------------------------------------------------------------------------ 
** 修改人: mowin , martin7wind 
** 日 期: 2008年02月03日 
** 描 述: For 智能充电器 
** 
**--------------当前版本修订------------------------------------------------------------------------------ 
** 修改人: 吕海安 
** 日 期: 2008年03月02日 
** 描 述: 修改格式,归档 
**------------------------------------------------------------------------------------------------------ 
**--------------当前版本修订------------------------------------------------------------------------------ 
** 修改人: 村长 aleyn.wu 
** 日 期: 2008年3月3日 
** 描 述: 修改了一些BUG,使本项目能在CVAVR下编译通过 
** 
**------------------------------------------------------------------------------------------------------ 
********************************************************************************************************/ 
#include "config.h" 
	#ifndef __SLEEP_DEFINED__ 
	#define __SLEEP_DEFINED__ 
	.EQU __se_bit=0x40 
	.EQU __sm_mask=0xB0 
	.EQU __sm_powerdown=0x20 
	.EQU __sm_powersave=0x30 
	.EQU __sm_standby=0xA0 
	.EQU __sm_ext_standby=0xB0 
	.EQU __sm_adc_noise_red=0x10 
	.SET power_ctrl_reg=mcucr 
	#endif 
#include "SIO.h" 
 
/*************************************************** 
 74HC166并入串出 
 连线如下 
 KEY_SDO   = PB0 
 KEY_CLK   = PB1 
 KEY_SLOAD = PB2 
 KEY_1 = A (UP)     62 
 KEY_2 = B (DOWN)   61 
 KEY_3 = C (LEFT)   59 
 KEY_4 = D (RIGHT)  55 
 KEY_5 = E (ENTER)  47 
 KEY_6 = F (CANCEL) 31 
***************************************************/ 
#define KEY_ADR  10 
#define KEY_DDR  DDRB 
#define KEY_PORT PORTB 
#define KEY_PIN  PINB 
#define SDO      PB0 
#define SCK      PB1 
#define SLOAD    PB2 
#define _BV(a)          (1 << a) 
#define SCK_high()      (KEY_PORT |= _BV(SCK)) 
#define SLOAD_high()    (KEY_PORT |= _BV(SLOAD)) 
#define SCK_low()       (KEY_PORT &=~ _BV(SCK)) 
#define SLOAD_low()     (KEY_PORT &=~ _BV(SLOAD)) 
#define read_SDO()      (KEY_PIN & _BV(SDO)) 
 
/******************************************************************************************************* 
** 函数名称: KEY_init 
** 功能描述: 74HC166 通信端口设置 
** 输入参数: 无 
** 输出参数: 无 
********************************************************************************************************/ 
void KEY_init(void) 
{ 
    // SLOAD SCK 输出,SDO 输入 
    KEY_DDR |= _BV(SLOAD)|_BV(SCK); 
    KEY_DDR &=~ _BV(SDO); 
    // SLOAD = 1 
    // SCK = 0 
    // SDO上拉电阻启用 
    SLOAD_high(); 
    SCK_low(); 
    KEY_PORT |= _BV(SDO); 
} 
/******************************************************************************************************* 
** 函数名称: SCK_low_to_high 
** 功能描述: 时钟产生 
** 输入参数: 无 
** 输出参数: 无 
********************************************************************************************************/ 
void SCK_low_to_high(void) 
{ 
    SCK_low(); 
    SCK_high(); 
    SCK_low(); 
} 
/******************************************************************************************************* 
** 函数名称: read_keycode 
** 功能描述: 键值读取函数 
** 输入参数: 无 
** 输出参数: 键值 
********************************************************************************************************/ 
INT8U read_keycode(void) 
{ 
    INT8U key_code = 0,i; 
    SLOAD_high(); 
    SLOAD_low();        // 允许并行数据 <----> Parallel enable input (active LOW) 
    SCK_low_to_high();  // 时钟信号,上升沿锁存数据并移出最高位 BIT7,非常重要 
    SLOAD_high();       // 并行锁存结束,非常重要 
    // 先读取 BIT7,非常重要 
    for(i = 8; i > 0; i--) 
    { 
        if(read_SDO()) 
        { 
            key_code |= _BV(i-1); 
        } 
        //产生下一个时钟信号 
        SCK_low_to_high(); 
    } 
    //返回键值,六个按键,只要低六位,高两位未用 
    return (key_code & 0x3f); 
} 
 
/******************************************************************************************************* 
** 函数名称: read_keycode 
** 功能描述:  连接并接收键盘信号,并进行持续按键判断 
**            键盘按键值和持续按键标志 均直接写入内存数据表 
**            键盘内存分配一个单元 INT8U 
**            前2位代表状态,后6位对应每一个按键 
**            最多存储三个按键状态,多余将被忽略 
**            状态: 1 1 --- 前两次结果未处理,等待 
**                  1 0 --- 上次按键结果未处理,等待 
**                  0 1 --- 正常按下,等待处理 
**                  0 0 --- 空闲 忽略,不处理 
**            普通按键位1代表正常,0代表按下 
** 输入参数: 无 
** 输出参数: 键值 
********************************************************************************************************/ 
void s_keyboard(void) 
{ 
    INT8U i; 
    i = read_keycode(); 
    if(i != NO_KEY) 
    { 
        lcd_locate(14,0); 
        lcd_print_number(i,2,0); 
    } 
 
} 
 
/********************************************************************************************************** 
**                                 END OF FILE 
********************************************************************************************************/ 
/****************************************Copyright (c)************************************************** 
**                              智 能 充 电 器 开 发 小 组 
**                                     OurAVR 论坛 
**                                   QQ 群: 26052247 
** 
**                               http://www.ouravr.com/bbs 
** 
**--------------文件信息-------------------------------------------------------------------------------- 
**文   件   名: SIO.c 
**创   建   人: Trinove 
**最后修改日期: 2008年01月13日 
**描        述: 菜单的底层函数  FOR AVR MCU / Mega16 
** 
**--------------历史版本信息---------------------------------------------------------------------------- 
** 创建人: aleyn.wu 
** 版  本: V1.0 
** 日 期: 2008年01月13日 
** 描 述: 原始版本 
** 
**--------------当前版本修订------------------------------------------------------------------------------ 
** 修改人: 吕海安 
** 日 期: 2008年03月09日 
** 描 述: For 智能充电器 
** 
**------------------------------------------------------------------------------------------------------ 
********************************************************************************************************/ 
#include "Config.h" 
	#ifndef __SLEEP_DEFINED__ 
	#define __SLEEP_DEFINED__ 
	.EQU __se_bit=0x40 
	.EQU __sm_mask=0xB0 
	.EQU __sm_powerdown=0x20 
	.EQU __sm_powersave=0x30 
	.EQU __sm_standby=0xA0 
	.EQU __sm_ext_standby=0xB0 
	.EQU __sm_adc_noise_red=0x10 
	.SET power_ctrl_reg=mcucr 
	#endif 
#include "Menu.h" 
 
#define MENU_LINE 2 
/******************************************************************************************************* 
** 函数名称: ExecuteMenu 
** 功能描述: 菜单显示程序,每 100 mS 调用一次即可 
** 输入参数: 无 
** 输出参数: 无 
********************************************************************************************************/ 
void ExecuteMenu(INT8U MenuID) 
{ 
	if (MenuID == MN_STAT_BATTERY0) 
	{ 
		ReadBatterySTAT(BATTERY0); 
	} 
	else if (MenuID == MN_STAT_BATTERY1) 
	{ 
		ReadBatterySTAT(BATTERY1); 
	} 
	else if (MenuID == MN_STAT_BATTERY_BOTH) 
	{ 
		ReadBatterySTAT(BATTERY_BOTH); 
	} 
} 
/******************************************************************************************************* 
** 函数名称: MenuNo 
** 功能描述: 菜单序号 
** 输入参数: INT8U No: 
** 输出参数: 
********************************************************************************************************/ 
INT8U MenuNo(INT8U No) 
{ 
    if ((No >= 0) && (No <= 9)) 
    { 
        return No + '0'; 
    } 
    else if ((No >= 10) && (No <= 36)) 
    { 
        return No - 10 + 'A'; 
    } 
    else 
    { 
        return '?'; 
    } 
} 
 
/******************************************************************************************************* 
** 函数名称: ChooseRadioMenu 
** 功能描述: 选择单选菜单 
** 输入参数: INT8U ParamCaptionID: 
**           INT8U MenuDefineID: 
**           INT8U *Value 
** 输出参数: 无 
********************************************************************************************************/ 
/* 
void ChooseRadioMenu(INT8U ParamCaptionID, INT8U MenuDefineID, INT8U *Value) 
{ 
    flash INT8U *Caption; 
    flash INT8U *pDefine; 
    INT8U Key; 
    INT8U Pos; 
    INT16U TopMenuItem; 
    INT16U CurrentMenuItem; 
    //INT8U i; 
    INT8U MenuCount; 
    delay_ms(10); 
    //LCD_WriteCaption(ParamCaptionID, 0); 
    //Pos = LCD_Position() - 1; 
     lcd_locate(0,0); 
    //WriteCGRAM(0x82,1,0); 
    //WriteCGRAM(0x83,2,0); 
    //WriteCGRAM(0x84,3,0); 
    pDefine = SubMenuDefine + (INT16U)2 * (INT16U)MenuDefineID; 
    MenuCount = pDefine[1]; 
    TopMenuItem = pDefine[0]; 
    CurrentMenuItem = *Value; 
    if (CurrentMenuItem > MenuCount - 1) 
    { 
        CurrentMenuItem=MenuCount - 1; 
    } 
 
    Key = INIT_KEY; 
    while (Key != BT_APPLY) 
    { 
        if (Key != NO_KEY) 
        { 
            lcd_write_byte((0x80 | Pos), CMD); 
            Caption = Menu + (CAPTION_LENGTH + 2) * (TopMenuItem + CurrentMenuItem - 1); 
            if (CurrentMenuItem == 0) 
            { 
                lcd_write_byte(3, DATA); 
            } 
            else if (CurrentMenuItem == MenuCount - 1) 
            { 
                lcd_write_byte(1, DATA); 
            } 
            else 
            { 
                lcd_write_byte(2, DATA); 
            } 
            //LCD_Write(MenuNo(CurrentMenuItem)); 
            lcd_write_byte(' ', DATA); 
            lcd_write_byte('=', DATA); 
            lcd_print_stringF(Caption); 
        } 
        Key = read_keycode(); 
        if (Key != NO_KEY) 
        { 
            if (Key == BT_UP) 
            { 
                if (CurrentMenuItem > 0) 
                { 
                    CurrentMenuItem --; 
                } 
            } 
            else if (Key == BT_DOWN) 
            { 
                if (CurrentMenuItem < MenuCount - 1) 
                { 
                    CurrentMenuItem ++; 
                } 
            } 
            else if (Key == BT_APPLY) 
            { 
                *Value = CurrentMenuItem; 
            } 
            else if (Key == BT_LEFT) 
            { 
                Key = BT_APPLY; 
            } 
            delay_ms(10) 
        } 
    } 
} 
*/ 
/******************************************************************************************************* 
** 函数名称: ShowMenu 
** 功能描述: 菜单显示程序,每 100 mS 调用一次即可 
** 输入参数: 无 
** 输出参数: 无 
********************************************************************************************************/ 
void ShowMenu(void) 
{ 
    static flash INT8U *pMenu; 
    static flash INT8U *pDefine; 
    static flash INT8U *Caption; 
    static INT16U TopMenuItem = 0; 
    static INT16U CurrentMenuItem = 0; 
    static INT8U Stack[3][5] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; 
    static INT8U StackIndex = 0; 
    static INT8U DrawMenuItem[6]={0x80,0xC0,1,0,0,1}; 
    static INT8U MenuCount; 
    static INT8U FlagMenuInit = 1;   // 显示菜单框架 
    static INT8U Key = INIT_KEY;     // 第一次显示菜单 
    INT8U i = 0; 
    INT8U j = 0; 
    if(FlagMenuInit) 
    { 
        FlagMenuInit = 0;  // 清第一次标志 
        lcd_cls();  //清屏 
        pMenu = Menu; 
        pDefine = SubMenuDefine; 
        MenuCount = SubMenuDefine[1]; 
        //WriteCGRAM(0x80,0,0);     // 写入特殊字符 
        //WriteCGRAM(0x81,1,0);     // 写入特殊字符 
    } 
    if (Key != NO_KEY) 
    { 
        for (j=0; j<2; j++) 
        { 
            lcd_write_byte(DrawMenuItem[0 + j], CMD); 
            if (DrawMenuItem[(INT8U)(j + 4)] < MenuCount) 
            { 
                Caption = Menu + (CAPTION_LENGTH + 2) * (TopMenuItem + DrawMenuItem[(INT8U)(j + 4)]); 
                if (DrawMenuItem[(INT8U)(j + 2)]) 
                { 
                    lcd_write_byte(0, DATA); 
                    lcd_write_byte(MenuNo(DrawMenuItem[(INT8U)(j + 4)] + 1), DATA); 
                    lcd_write_byte('.', DATA); 
                    lcd_print_stringF(Caption); 
                } 
                else 
                { 
                    lcd_print_stringF(" "); 
                    lcd_write_byte(MenuNo(DrawMenuItem[(INT8U)(j + 4)] + 1), DATA); 
                    lcd_write_byte('.', DATA); 
                    lcd_print_stringF(Caption); 
                } 
            } 
            else 
            { 
                for (i=0; i<16; i++) 
                { 
                    lcd_write_byte(' ', DATA); 
                } 
            } 
        } 
    } 
    Key = read_keycode(); 
    if (Key != NO_KEY) 
    { 
        if (Key == BT_UP) 
        { 
            if (DrawMenuItem[3]) 
            { 
                DrawMenuItem[2]=1; 
                DrawMenuItem[3]=0; 
            } 
            else if (DrawMenuItem[4]>0) 
            { 
                DrawMenuItem[4]--; 
                DrawMenuItem[5]--; 
            } 
        } 
        else if (Key == BT_DOWN) 
        { 
            if (DrawMenuItem[2]) 
            { 
                DrawMenuItem[2]=0; 
                DrawMenuItem[3]=1; 
            } 
            else if (DrawMenuItem[5]<MenuCount-1) 
            { 
                DrawMenuItem[4]++; 
                DrawMenuItem[5]++; 
            } 
        } 
        else if ((Key == BT_APPLY) || (Key == BT_RIGHT)) 
        { 
            if (DrawMenuItem[2]) 
            { 
                CurrentMenuItem = TopMenuItem + DrawMenuItem[4]; 
            } 
            else 
            { 
                CurrentMenuItem = TopMenuItem + DrawMenuItem[5]; 
            } 
            if (CurrentMenuItem < MENU_COUNT) 
            { 
                pMenu = Menu + ((CAPTION_LENGTH + 2) * CurrentMenuItem) + CAPTION_LENGTH + 1; 
                if (*pMenu > MENU_SUBITEM) 
                { 
                    Stack[0][StackIndex] = pDefine-SubMenuDefine; 
                    Stack[1][StackIndex] = DrawMenuItem[2]; 
                    Stack[2][StackIndex] = DrawMenuItem[4]; 
                    StackIndex ++; 
                    pDefine = SubMenuDefine + ((INT16U)(*pMenu - MENU_SUBITEM) * 2); 
                    TopMenuItem =* pDefine - 1; 
                    MenuCount = pDefine[1]; 
                    DrawMenuItem[2] = 1; 
                    DrawMenuItem[3] = 0; 
                    DrawMenuItem[4] = 0; 
                    DrawMenuItem[5] = 1; 
                } 
                else if (*pMenu <= MENU_SUBITEM) 
                { 
                    ExecuteMenu(CurrentMenuItem + 1); 
                } 
            } 
        } 
        else if ((Key == BT_CANCEL) || (Key == BT_LEFT)) 
        { 
            if (StackIndex > 0) 
            { 
                StackIndex --; 
                pDefine=SubMenuDefine + (INT16U)(Stack[0][StackIndex]); 
                TopMenuItem=*pDefine - 1; 
                MenuCount=pDefine[1]; 
                DrawMenuItem[2] = Stack[1][StackIndex]; 
                DrawMenuItem[3] = 1 - Stack[1][StackIndex]; 
                DrawMenuItem[4] = Stack[2][StackIndex]; 
                DrawMenuItem[5] = Stack[2][StackIndex] + 1; 
            } 
        } 
    } 
} 
 
 
/******************************************************************************************************** 
**                                 END OF FILE 
********************************************************************************************************/ 

送体验金的网站