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; //返回数据
}
占楼 >> 项目通过编译 需要安装 SN-Link_Driver for Keil C51_V2.00.34 不错.. 有没有电路图..这样看,,很慌. 自整定怎么弄,我弄的不行 sweet_136 发表于 2019-3-13 18:17
不错.. 有没有电路图..这样看,,很慌.
4 >> 在 _isch 这个文件夹 里有原理图和需求文档 (备注:代码有些地方与文档并不一致) 感谢楼主分享。。。 很好的资料,谢谢分享。
可惜我还不懂什么是PID,为什么充电器要用PID?哪位大哥能赐教一下。 主要是有电路吗 楼主牛比,我是来学习的,留下足迹1个。。。
mathison 发表于 2019-3-13 18:10
占楼 >> 项目通过编译 需要安装 SN-Link_Driver for Keil C51_V2.00.34
接的俄罗斯项目?居然是俄语 很好的资料{:smile:} mubei 发表于 2019-3-13 21:00
接的俄罗斯项目?居然是俄语
是的 俄罗斯 把一些低端的 cost down的 产品扔给我们做
(一些低端的 低成本的产品,外国人根本没法跟我们竞争,可惜啊,搞贸易战)
本来是 计划用两路PWM 来提高 充电效率的 硬件工程师没有细看 SN8F5702 的 datasheetPWM没法输出死区,松翰故意这么挖坑。 Protothreads mark! 很好的资料,谢谢分亨! 很慌看了一下是个锂电池充电器 PID + Protothreads 做的一个充电器 原理图图片形式发上来就超级棒{:victory:} 谢谢分亨! 感谢分享,做得漂亮。
精神值得鼓励。 谢谢分享,!我一位只有温控才有PID控制呢
好资料,谢谢分亨 mark,最近也在看protothread,向LZ学习下。 谢谢楼主分享,学习学习!~ 楼主牛比 mathison 发表于 2019-3-13 18:10
占楼 >> 项目通过编译 需要安装 SN-Link_Driver for Keil C51_V2.00.34
可以把timer_set和timer_expired函数贴出来一下吗,学习一下实现的思路
页:
[1]