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

2020-01-12 17:18发布

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 DBG  uart_printf


code BYTE GpioKeyEvent[][5] =
{
    //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)
{
    static  unsigned 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! "));
            GpioKeyState = GPIO_KEY_STATE_JITTER;

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

            break;

        case GPIO_KEY_STATE_PRESS_DOWN:
            if(PreKeyIndex != KeyIndex)
            {
                //DBG(("ADC KEY SP!***** "));
                //P_KEY_OUT = 1;
                //Uart1_PutChar(0xA2);
                GpioKeyState = GPIO_KEY_STATE_IDLE;
                return GpioKeyEvent[PreKeyIndex][1]; //SPR(短按松开)
            }
            else if(timer_expired(&gpioKeyWaitTimer))
            {
                //DBG(("ADC KEY CP!******** "));
                //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[PreKeyIndex][2];  //CPS(长按开始)
            }

            break;

        case GPIO_KEY_STATE_CP:
            if(PreKeyIndex != KeyIndex)
            {
                //DBG(("ADC KEY CPR!************* "));
                //Uart1_PutChar(0xA4);
                //P_LED_R_OFF;
                GpioKeyState = GPIO_KEY_STATE_IDLE;
                return GpioKeyEvent[PreKeyIndex][4]; //CPR(长按松开)
            }
            else if(timer_expired(&gpioKeyWaitTimer))
            {
                //DBG(("ADC KEY CPH!************* "));
                timer_set(&gpioKeyWaitTimer, GPIO_KEY_CPH_TIME);
                return GpioKeyEvent[PreKeyIndex][3]; // 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();
}

/**
  * @brief  This function checks ACK/NACK from I2C slave.
  * @param  None
  * @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 char  I2C_ReadByte(void)
*入口参数:  无
*出口参数:  unsigned char  RecByte--读取的字节
*函数功能:  向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为输出
    return  Dat;                               //返回数据
}




友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
23条回答
asbzhang
1楼-- · 2020-01-15 06:47

好资料,谢谢分亨
skype
2楼-- · 2020-01-15 08:39
mark,最近也在看protothread,向LZ学习下。
changshs
3楼-- · 2020-01-15 10:20
 精彩回答 2  元偷偷看……
dam
4楼-- · 2020-01-15 14:25
楼主牛比
fsmcu
5楼-- · 2020-01-15 19:01
mathison 发表于 2019-3-13 18:10
占楼 >> 项目通过编译 需要安装 SN-Link_Driver for Keil C51_V2.00.34

可以把timer_set和timer_expired函数贴出来一下吗,学习一下实现的思路

一周热门 更多>