mathison 发表于 2019-3-13 18:06:57

PID + Protothreads 做的一个充电器 (完整的项目)

1 >> 项目PID参考了以下帖子: 关于PID我没有什么可以说的,因为我是拿来就用,只调整 K_P ,K_I ,K_D 三个参数,实测效果可以.

https://www.amobbs.com/thread-5556400-1-1.html

2 >> Protothreads 使用的是 康奈尔大学ECE4760课程中的Protothreads(备注 gSysTick++; //1ms所有的时间片 基于此)
修正了其中的一个bug:

这是原版的:
#ifdef MX250
#define PT_YIELD_TIME_msec(delay_time)\
    do { static unsigned int time_thread ;\
    time_thread = gSysTick + (delay_time) ; \
    PT_YIELD_UNTIL(pt, (gSysTick >= time_thread)); \
    } while(0);
#endif

这是修正后的:
#if 1
#define PT_YIELD_TIME_msec(delay_time)\
    do { static volatile unsigned int time_thread ;\
    time_thread = gSysTick; \
    PT_YIELD_UNTIL(pt, ((unsigned int)(gSysTick - time_thread) >= (unsigned int)(delay_time))); \
    } while(0);
#endif

3 >>考虑到这个案子也没有什么没有太难的东西,而且这个只是第一次送样的代码(离产品还有一些距离),所以就当是对无私的热心地坛友的一声谢谢. (如果认识我们老板或者这个案子的客户,请保持沉默,别打我小报告)

4 >> 在 _isch 这个文件夹 里有原理图和需求文档 (备注:代码有些地方与文档并不一致)

5>> 这个案子并没有 按键 和 I2C,我把这两个文件也打包一起放上来,希望大家能用得上:

//app_key.c

#include "app_cfg.h"
#include "app_global.h"
#include "app_timer.h"

#ifdef UART1_EN
#include "sn8f5702_uart.h"
#endif

#define KEY_GLOBALS
#include "app_key.h"

//#define DBGuart_printf


code BYTE GpioKeyEvent[] =
{
    //PDS(按键开始)      SPR(短按松开)      CPS(长按开始)       CPH(长按保持)         CPR(长按松开)
    {MSG_NONE,         MSG_MODE,          MSG_POWER_ON,       KEY_POWER_LONG,         KEY_POWER_LONG_BREAK},//K1
    {MSG_NONE,         MSG_LIGHT,         MSG_LIGHT_CPS,      MSG_LIGHT_CPH,          MSG_LIGHT_CPR       },//K2
};

TIMER idata gpioKeyWaitTimer;
//TIMER gpioKeyScanTimer;
GPIO_KEY_STATE idata GpioKeyState;

void GpioKeyInit(void)
{
    P_KEY_POWER_INPUT;
    GpioKeyState = GPIO_KEY_STATE_IDLE;
    //timer_set(&gpioKeyScanTimer, 0);
}

static u8_t GetGpioKeyIndex(void)
{
    u8_t KeyIndex = 0xFF;

    if(P_KEY_POWER == 0)
    {
      KeyIndex = 0;
    }

    return KeyIndex;

}

KEY_EVENT GpioKeyScan(void)
{
    staticunsigned char idata PreKeyIndex = 0xFF;
    BYTE KeyIndex;
    KeyIndex = GetGpioKeyIndex();

    switch(GpioKeyState)
    {
      case GPIO_KEY_STATE_IDLE:

            if(KeyIndex == 0xFF)
            {
                return MSG_NONE;
            }

            PreKeyIndex = KeyIndex;
            timer_set(&gpioKeyWaitTimer, GPIO_KEY_JTTER_TIME);
            //DBG(("GOTO JITTER!\n"));
            GpioKeyState = GPIO_KEY_STATE_JITTER;

      case GPIO_KEY_STATE_JITTER:
            if(PreKeyIndex != KeyIndex)
            {
                //DBG(("GOTO IDLE Because jitter!\n"));
                GpioKeyState = GPIO_KEY_STATE_IDLE;
            }
            else if(timer_expired(&gpioKeyWaitTimer))
            {
                //DBG(("GOTO PRESS_DOWN!\n"));
                //P_KEY_OUT = 0;
                //Uart1_PutChar(0xA1);
                timer_set(&gpioKeyWaitTimer, GPIO_KEY_CP_TIME);
                GpioKeyState = GPIO_KEY_STATE_PRESS_DOWN;
                return GpioKeyEvent;//PDS(按键开始)
            }

            break;

      case GPIO_KEY_STATE_PRESS_DOWN:
            if(PreKeyIndex != KeyIndex)
            {
                //DBG(("ADC KEY SP!*****\n"));
                //P_KEY_OUT = 1;
                //Uart1_PutChar(0xA2);
                GpioKeyState = GPIO_KEY_STATE_IDLE;
                return GpioKeyEvent; //SPR(短按松开)
            }
            else if(timer_expired(&gpioKeyWaitTimer))
            {
                //DBG(("ADC KEY CP!********\n"));
                //P_KEY_OUT = 1;
                //Uart1_PutChar(0xA3);
                //P_LED_R_ON;
                timer_set(&gpioKeyWaitTimer, GPIO_KEY_CPH_TIME);
                GpioKeyState = GPIO_KEY_STATE_CP;
                return GpioKeyEvent;//CPS(长按开始)
            }

            break;

      case GPIO_KEY_STATE_CP:
            if(PreKeyIndex != KeyIndex)
            {
                //DBG(("ADC KEY CPR!*************\n"));
                //Uart1_PutChar(0xA4);
                //P_LED_R_OFF;
                GpioKeyState = GPIO_KEY_STATE_IDLE;
                return GpioKeyEvent; //CPR(长按松开)
            }
            else if(timer_expired(&gpioKeyWaitTimer))
            {
                //DBG(("ADC KEY CPH!*************\n"));
                timer_set(&gpioKeyWaitTimer, GPIO_KEY_CPH_TIME);
                return GpioKeyEvent; // CPH(长按保持)
            }

            break;

      default:
            GpioKeyState = GPIO_KEY_STATE_IDLE;
            break;
    }

    return MSG_NONE;

}


//bsp_i2c.c

#include "sn8f5702.h"

#include "app_cfg.h"
#include "app_global.h"

#ifdef UART1_EN
#include "sn8f5702_uart.h"
#endif

#include "bsp_i2c.h"

#define I2C_Delay()   _dly_1us(1)

#define GET_ACK_TIME                  250


/******************************************************************************************
*函数名称:void I2C_Idle(void)
*入口参数:无
*出口参数:无
*函数功能:I2C总线空闲
******************************************************************************************/
void I2C_Idle(void)
{
    P_I2C_SCL_OUTPUT;
    P_I2C_SCL = 1;
    P_I2C_SDA_OUTPUT;
    P_I2C_SDA = 1;
}

/******************************************************************************************
*函数名称:void I2C_Start(void)
*入口参数:无
*出口参数:无
*函数功能:I2C通信启始
            SDA 1->0 while SCL High
******************************************************************************************/
void I2C_Start(void)
{
    P_I2C_SCL_OUTPUT;
    P_I2C_SCL = 1;
    P_I2C_SDA_OUTPUT;
    P_I2C_SDA = 1;
    I2C_Delay();
    P_I2C_SDA = 0;
    I2C_Delay();
    P_I2C_SCL = 0;
}

/******************************************************************************************
*函数名称:void I2C_Stop(void)
*入口参数:无
*出口参数:无
*函数功能:I2C通信结束
            SDA 0->1 while SCL High
******************************************************************************************/
void I2C_Stop(void)
{
    P_I2C_SCL_OUTPUT;
    P_I2C_SCL = 0;
    P_I2C_SDA_OUTPUT;
    P_I2C_SDA = 0;
    I2C_Delay();
    P_I2C_SCL = 1;
    I2C_Delay();
    P_I2C_SDA = 1;
    I2C_Delay();
}

/**
* @briefThis function checks ACK/NACK from I2C slave.
* @paramNone
* @return None
*/

boolean I2C_ChkAck(void)
{
    boolean Ack;
    unsigned char GetAckTime = GET_ACK_TIME;                  //返回ACK信号延时等待时间
    P_I2C_SDA_INPUT;       //Allow slave to send ACK
    P_I2C_SCL = 0;      //slave send ACK
    P_I2C_SCL = 1;

    while(P_I2C_SDA && (--GetAckTime));

    Ack = (!P_I2C_SDA);   //Get ACK from slave
    P_I2C_SCL = 0;
    P_I2C_SDA_OUTPUT; // add by k.s
    return Ack;
}


/******************************************************************************************
*函数名称:boolean I2C_WriteByte(unsigned char SendByte)
*入口参数:unsigned char SendByte--发送的字节
*出口参数:无
*函数功能:向I2C总线发送一个字节
*This function send one byte to I2C slave.
******************************************************************************************/
boolean I2C_WriteByte(unsigned char SendByte)
{
    unsigned char i = 8;
    P_I2C_SDA_OUTPUT;
    P_I2C_SCL = 0;   //设置I2C_SDA为输出

    while(i--)       //I2C_SDA脚从高位至低位发送数据
    {
      if(SendByte & 0x80)                  /* MSB output first */
      {
            P_I2C_SDA = 1;
      }
      else
      {
            P_I2C_SDA = 0;
      }

      SendByte <<= 1;
      P_I2C_SCL = 1;                            //拉高I2C_SCL
      I2C_Delay();
      P_I2C_SCL = 0;                            //拉低I2C_SCL,以允许I2C_SDA脚w位数据发生变化
    }

    return I2C_ChkAck();

}

/******************************************************************************************
*函数名称:unsigned charI2C_ReadByte(void)
*入口参数:无
*出口参数:unsigned charRecByte--读取的字节
*函数功能:向I2C总线读取一个字节
******************************************************************************************/
void I2C_SendNoAck(void)
{
    P_I2C_SDA = 1;
    P_I2C_SCL = 1;
    I2C_Delay();
    P_I2C_SCL = 0;
}

unsigned char I2C_ReadByte(void)
{
    unsigned char i = 8;
    unsigned char Dat = 0;

    P_I2C_SDA_INPUT;                        //设置I2C_SDA为输入

    while(i--)
    {
      P_I2C_SCL = 1;                              //拉高I2C_SCL
      I2C_Delay();
      Dat <<= 1;

      if(P_I2C_SDA)
      {
            Dat |= 0x01;
      }

      P_I2C_SCL = 0;                              //拉低I2C_SCL
      I2C_Delay();
    }

    P_I2C_SDA_OUTPUT;                                    //设置I2C_SDA为输出
    returnDat;                               //返回数据
}




mathison 发表于 2019-3-13 18:10:00

占楼 >> 项目通过编译 需要安装 SN-Link_Driver for Keil C51_V2.00.34

sweet_136 发表于 2019-3-13 18:17:23

不错.. 有没有电路图..这样看,,很慌.

liurangzhou 发表于 2019-3-13 18:31:59

自整定怎么弄,我弄的不行

mathison 发表于 2019-3-13 18:56:00

sweet_136 发表于 2019-3-13 18:17
不错.. 有没有电路图..这样看,,很慌.

4 >> 在 _isch 这个文件夹 里有原理图和需求文档 (备注:代码有些地方与文档并不一致)

ahfong2006 发表于 2019-3-13 19:14:35

感谢楼主分享。。。

zpywz 发表于 2019-3-13 19:47:36

很好的资料,谢谢分享。
可惜我还不懂什么是PID,为什么充电器要用PID?哪位大哥能赐教一下。

qiqirachel 发表于 2019-3-13 19:53:46

主要是有电路吗

kinsno 发表于 2019-3-13 19:55:58

楼主牛比,我是来学习的,留下足迹1个。。。

mubei 发表于 2019-3-13 21:00:04

mathison 发表于 2019-3-13 18:10
占楼 >> 项目通过编译 需要安装 SN-Link_Driver for Keil C51_V2.00.34

接的俄罗斯项目?居然是俄语

君莫笑 发表于 2019-3-13 21:36:39

很好的资料{:smile:}

mathison 发表于 2019-3-13 23:32:35

mubei 发表于 2019-3-13 21:00
接的俄罗斯项目?居然是俄语

是的 俄罗斯 把一些低端的 cost down的 产品扔给我们做

(一些低端的 低成本的产品,外国人根本没法跟我们竞争,可惜啊,搞贸易战)

本来是 计划用两路PWM 来提高 充电效率的 硬件工程师没有细看 SN8F5702 的 datasheetPWM没法输出死区,松翰故意这么挖坑。

KunShan_a_dai 发表于 2019-3-14 09:08:25

Protothreads mark!

chenghuiwan 发表于 2019-3-14 09:21:06

很好的资料,谢谢分亨!

kydl2345 发表于 2019-3-14 09:38:15

很慌看了一下是个锂电池充电器

lb0857 发表于 2019-3-25 08:29:53

PID + Protothreads 做的一个充电器   原理图图片形式发上来就超级棒{:victory:}

jack12345 发表于 2019-3-25 11:46:27

谢谢分亨!

zhonghua_li 发表于 2019-3-25 13:55:01

感谢分享,做得漂亮。
精神值得鼓励。

zhangfuhg 发表于 2019-3-25 14:23:34

谢谢分享,!我一位只有温控才有PID控制呢

asbzhang 发表于 2019-3-25 16:12:00


好资料,谢谢分亨

skype 发表于 2019-6-21 16:02:18

mark,最近也在看protothread,向LZ学习下。

changshs 发表于 2019-10-21 13:53:19

谢谢楼主分享,学习学习!~

dam 发表于 2019-10-24 22:04:39

楼主牛比

fsmcu 发表于 2019-10-25 10:03:32

mathison 发表于 2019-3-13 18:10
占楼 >> 项目通过编译 需要安装 SN-Link_Driver for Keil C51_V2.00.34

可以把timer_set和timer_expired函数贴出来一下吗,学习一下实现的思路
页: [1]
查看完整版本: PID + Protothreads 做的一个充电器 (完整的项目)