搜索
bottom↓
回复: 33

DIY我们的开源充电器[拟持续更新]

[复制链接]

出0入0汤圆

发表于 2010-1-2 23:50:41 | 显示全部楼层 |阅读模式
1. 缘起

myblog同步更新

家里有很多电池, 便宜的NICD, 给儿子的各种玩具,给各个用电池的地方供应电力. 比如煤气表, 剃须刀, 遥控器. 遥控气车. 电压从1.2 到 9V不等. 没有一个充电器包打天下, taobao有售 2-10串镍氢镍镉电池组智能充电器, 号称12bitAD精度, 查了下芯片(VIPer12A)资料, 那明明就是一个开关电源撒(没有看到芯片说明里提到12bitADC, 求达人释疑).被大家推崇的MR57, 200元的价格, 只能充1节的.







VIPer12A的方案可能是开关电源加上类似南孚的解决方法: http://bbs.mydigit.cn/read.php?tid=100383
2-10串镍氢镍镉电池组智能充电器, 直流测正面只有3个三极管,或许是以电池为参考电压加上一个恒压进行充电?未知,VIPER12没有太神奇的功能吧. 相关图片轻移步淘宝.

幸运的是, 我看到了OURAVR上的自制充电器:
http://www.ourdev.cn/bbs/bbs_list.jsp?bbs_id=1026



认识了Buck降压电路, 乃充电器核心的模拟模块了.

人民是很厉害的, 自己弄这个东西不会花很多钱, 关键是折腾, 注意这个要领,-:)

AVR论坛开源冲电器用的是Mega32. 俺一开始用的是51去折腾, 成功不重要,折腾最重要. 51 当然不成, 没有ADC, ADC芯片8bit都几块钱呢, 何况8bit, 不准确阿. 面包板就是阵地, 已经开工, 这里是回忆录.


面包板和洞洞板版本


阿莫论坛20周年了!感谢大家的支持与爱护!!

一只鸟敢站在脆弱的枝条上歇脚,它依仗的不是枝条不会断,而是自己有翅膀,会飞。

出0入0汤圆

 楼主| 发表于 2010-1-3 00:09:20 | 显示全部楼层
2009.12.30
2.面包板上的PWM和Buck


myblog同步更新

第一步就是搭上Buck电路和一个可调占空比的555电路做验证.上面包板美图一副. 上面是Buck电路, 下面是555搭的PWM.带散热片的是IRF9640 PMOS管.近邻PMOS,右边的是一个电感. IRF左边是推挽驱动电路.


BUCK电路原理

我一菜鸟,当然是参考www.ouravr.cn 的开源充电器项目. 其BUCK电路原理如下:
http://www.ourdev.cn/bbs/bbs_content.jsp?bbs_sn=859893&bbs_page_no=1&bbs_id=1026

根据手头的元件, 把2n7002去掉了. 换成一个三极管. 也没有dis charger电路. 并且做了multisim的仿真,看起来挺好, 俺一直用这个仿真的电路图作为蓝本的.(电阻值或不准,仅供参考)
multisim 仿真工程文件ourdev_521789.zip(文件大小:333K) (原文件名:pwm-ouravr-charger.ms10.zip)



buck特写(这是推广摄影作品?)


NE555 实现的PWM

我用的555PWM发生器脱胎于这个电路.

另上独立的555 PWM面包板图一副:


调试和心得

效率粗略测量是80%, 不多说废话看svn log记录.

------------------------------------------------------------------------
r47 | heyongli | 2009-09-09 16:17:51 +0800 (三, 2009-09-09) | 6 行

buck 降压模拟成功
1.由于开关管开启电压较高,如要12v电源
2.电感小了带负载能力差,380uh可行
3.电容小了也不成,会导致电压较低(放电太快)
4.至少1khz了, 最好15khz 的PWM
------------------------------------------------------------------------
r48 | heyongli | 2009-09-09 22:19:15 +0800 (三, 2009-09-09) | 2 行

用pulse 试试看, pmos好像接反了,正过来试试
------------------------------------------------------------------------
r51 | heyongli | 2009-09-11 20:46:29 +0800 (五, 2009-09-11) | 13 行

IRF640N IN4007
续流二极管应该换成肖特基IN5819, mos管IRF9640温度降了不少,
测试情况:
1.续流用IN4007的时候, 0.9A, 大散热片6x到70度
2.续流换成IN5819, 1.25A, 小散热片, 53度
3.IN5819换成大散热片, 1.25A 温度不超过37度
以上室温25度左右,9.10号的北京.

原来用IN4007的时候应该是有自激震荡?(不知道是不是和为什么),
但是有个现象万用表的测温探头只要接触IRF9640(开关管)就能正常
测温,好似有很高的频率干扰了万用表的工作, 续流二极管换成
IN5819后没有这个现象了.
------------------------------------------------------------------------
r52 | heyongli | 2009-09-11 22:38:50 +0800 (五, 2009-09-11) | 7 行

电容最大4.7uf,用470uf的再栅极电压会有震荡(模拟结果,没有示波器...)
提高频率到100khz,温度反而高
现在用40khz, 1.3A,温度43度, 散热片是5cmx5cm的...

算成功了?

出0入0汤圆

 楼主| 发表于 2010-1-3 12:00:05 | 显示全部楼层
2009.12.31
没有一个显示设备当然不成, 一开始选了4x8的数码管. 你马上可以想到悲惨的命运, charger的状态颇多, 这样一个设备,很直观的从显示上看到想要的东西, 显示电压就没有来电流, 也没有符号可以指示是电流还是电压. 不过玩个乐罢了. 今年10.1的时候再家里弄的. 基本部件包括一个.36寸的4位数码管和一个led电平指示部件. taobao有售这样的模块, 20元. 看起来酷酷的, 不过我焊的就难看多了.



难看也看看吧. 费了我老鼻子力气来,整个国庆的业余时间都塔进去了, 正面看起来还是凑合的. 焊工有待提高的那种

背面(故意找了张不清楚的照片,清楚的太恶心了)

工作中

电路图网上太多了, 介绍原理的也是多如牛毛, 虽然要玩玩轮子, 就不打算详细介绍原理了, 推荐博文一篇:
http://hi.baidu.com/txz01/blog/item /1be0b8c4865c98ab8326ac72.html
电路原理我也不打算画了. 抓一副图吧,基本和这个一样的, 上边有限流电阻, 多加一位灯柱的电路即可,焊接的时候是弄一个测一个,错了不好改的哈:
为了像个技术贴, 把驱动思路说说, 当时采用的是51. 采用动态扫描实现显示. 使用用了一个timer, 10ms更新一次,每次显示不同的位(灯柱也算一位). 并且用了4个char变量来存储显示内容(ASCII码). 这样,更新显示时只需要将显示内容写入对应的5个变量即可. 实在没有高科技哈.
也尝试实用1602来着, 做完这个后当时马上弄了个1602, 很不幸, 把1602和85s52都烧掉了, 因为接到了12V电源上.... 我发誓要防呆....

驱动代码:
下载:下载

出0入0汤圆

 楼主| 发表于 2010-1-3 17:07:11 | 显示全部楼层
2009.12.31

开始我是没有AD芯片的, 玩的单片机也是没AD的s52. 但是我无意间看到电源网的azhu原创的(应该是原作者)《用普通单片机实现低成本高精度A/D转换》, 但是原文已经没有了. 只有一些转载. 基本原理如下. 利用电压比较和RC电路判断输入电压的值.


原理是这个样子的,PWM经过滤波后得到一个稳定的电压值: U1=VDD*D1/(D1+D2). 只要逐步的增加占空比,就能让U1‘线性’增加, 等到RA1第一次出现翻转(1->0),就可以根据占空比得知模拟量的值. 如果PWM是16bit的, 那么理论上精度是也是16bit(应该只是理论上,没有测试过). 误差来源:
1)电源电压, 如果VDD 0.5%, 最后能得到1%精度
2)软件产生的PWM占空比不准确
3)RC电路波纹影响

变下方向还可以DA.(RC大波纹小,但是速度可以想像,不咋的的)

是的,一开始我就用这个电路. 做了详细的测试. 无奈s52连pwm也没有, 速度低, 12M,1us的指令周期,用timer产生15khz的pwm有困难,还要兼顾扫描显示, 是在力不从心.

不断的调试和调整参数,优化程序(没有用汇编,只是c),也没有取得能用的精度..和测量结果. 虽然也能探测0.05的变化这个显然不能探测-dV, 差了不少呢. 所以也只能显压充电. 最大的问题是ADC的时候必须关闭pwm,否则更为不准确,如此以来-dV更是无从谈起阿.电流的测量更是不准确. 速度也成问题.



下面是调试的一些log和最终结果:

------------------------------------------------------------------------
r67 | heyongli | 2009-10-18 23:30:10 +0800 (日, 2009-10-18) | 3 行

发现不同loop值在不同范围内有最好的精度
ad转化后在180一下, loop=25即可.
>188. loop12 可以修正测量值,使0.05V的adc值为8


------------------------------------------------------------------------
r65 | heyongli | 2009-10-18 19:36:31 +0800 (日, 2009-10-18) | 195 行

经过两天的调试,终于得到一个看起来不错的版本.

犯过的错误:
1) 最大的一个: ADC_PWM pull-up使用100k电阻, 结果RC的R不是
   10k, 而是110k, 导致5v VCC下,RC最高只能达到 1.6V的电压

2) 多少次loop,频率不能猜, 用multisim模拟RC,大约5ms RC电压
   基本达到稳定,得到loop理论值应该是: 5000/511 = 10
   实际测量15比较好

经历的挫折:
1) 程序中udelay不能接受0值
2) 在pwm loop中使用 取余,整除: /,%, 非常慢,不要用
3) 测试了使用udelay,不用udelay(while(--cyc)),测试了多种RC值
甚至使用推挽对RC充电(这个版本吧推挽去掉了推挽电路,改天加上看
看是否好些)
4) PWM对测量产生的干扰, RC滤波
这个版本的程序可以测量0.5 到 大约3.9V的电压 <0.5V 无法测量.
0.5 到 2.3V 线性比较好,分辨率约0.1V
2.3 V以上 误差%5左右.
-----------------------------------------------
100 loop 511 cycle
+1k pull-up RC:10k,1uf


0.50   0..1
0.55   8
0.60   17..20
0.65   24
0.70   32
0.75   40
0.80   48
0.85   56
0.90   64  
0.95   72
1.00   80


1.10   96   
1.2    112
1.3    128
1.4    144..145  +1
1.5    159..161  +-1
1.6    172  -4
1.7    188  -4
1.8    205..207  -3..-1
1.9    220  -4
2.0    236  -4    (259)
2.1    248..252  -5     20 loop: 250..252  15loop:256 -1, good
2.2    264       -9
2.3    280       -9
2.4    296       -9
2.5    305..312  -9
2.6    323..324  -13    loop=15, 330 -6
2.7    340..341  -12    loop=15, 347 -6
2.8    359..365  -4     
2.9    398..407  +22
3.0    420..424  +22
3.1    440..447  +29
3.2    460       +29
3.3    476       +29
3.4    500       +37

------------ RESULT -----------------

20 loop same as above: about ~1 flick
20 loop is better than 100
15 seem better than 20 loop

100 loop 511 cycle
+1k pull-up RC:10k,1uf
better adc method:

d=adc(0,2); fast serch
adc(d-5,15); multiple adjust adc

if(timeafter(jiffers,lasttime+1000) ){               
               pwm_safeoff();
                 //fast search
                   if(onduty>10)
                    onduty = adc(onduty-5,15);
                else
                    onduty = adc(0, 2);
                pwm_safeon();
                printhex(onduty);
                vledmod('H');
                lasttime = jiffers;
}

unsigned short adc(unsigned short adc_duty,unsigned short loop)
{
   unsigned short adcloop;
   ADC_PWMPIN = 0;
   ADC_SIGNAL = 1;
   //mdelay(1000); //uncharge
   // free+6us     
   for(; adc_duty<= (ADC_CYCLE); adc_duty+=ADC_STEP){
      xadc_free = ADC_CYCLE-adc_duty;
      adcloop =loop;                                                                                         
      while(adcloop){
         ADC_PWMPIN = 1;   
         udelay(adc_duty);
         ADC_PWMPIN = 0;
          udelay(xadc_free);
         adcloop--;

      }
      if(0 == ADC_SIGNAL) {
          // printhex(adc_duty);
           return adc_duty;

      }   
}
   return adc_duty;//adc_duty;
}

------------------------------------------------------------------------
r64 | heyongli | 2009-10-17 15:20:28 +0800 (六, 2009-10-17) | 140 行

加了不少东西. check in主要为了ADC

这个版本的ADC使用 udelay, 8us的增量才准确, 总周期1khz.
下面是一些adc的测试,精度 1000/8 128step, 5v的话是0.05v
=======================================================
cycle:100
step: 1
loop: 100
0.25   4
0.30   4
0.35   4
0.40   4
0.45   5
0.50   8
0.55   8
0.60   13
0.65   16
0.70   16
0.75   16
0.80   22
0.85   24
0.90   24
0.95   29
1.00   32
1.05   32
1.10   32
1.15   37


cycle:256
step: 1
loop: 100
0.25   8   
0.30   8
0.35   16  0.1v 8
0.40   24
0.45   32  0.1  6
0.50   32
0.55   40  0.1  8
0.60   48
0.65   49  0.1  9
0.70   56
0.75   64  0.1  15
0.80   65
0.85   72  0.1  8
0.90   73
0.95   80  0.1  8
1.00   88
1.05   88  0.1  8
1.10   96
1.15   97  0.1  8
1.20   104
1.25   105 0.1  8
1.30   112
1.35   113 0.1  8
1.40   120
1.45   121 0.1  8

1.55   129      8



cycle:1024  (/8= 128step)
1.55   273
1.50   269
1.48   265  
1.44   257
1.40   250
1.35   241
1.30   233
1.24   225  

1.20   217

1.05   194

//1uf
1.054  176
1.000  168
0.95   160
0.90   152
0.85   144
0.80   136
           15
0.75   121
0.70   113
0.65   104
0.60    96
0.55    88
           14
0.50    74
0.45    65
0.40    56
0.35    48
           15
0.30    33
0.25    25
0.20    16
0.15     8 ..4
0.10     0



优化udelay
cycle:1024  (/8= 128step)
step :2
0.152  4
0.200  12

0.25   24
0.30   32
0.35   44

0.40   54
0.45   64
0.50   76
0.55   86
        
0.60   96
0.65  104

0.70  114

0.75  124
0.80  132

0.85  142
0.90  150

0.95  160
1.00  168
1.05  176
1.10  184
1.15  192
1.20  200..

1.25  210
1.30  218

出0入0汤圆

 楼主| 发表于 2010-1-3 17:56:51 | 显示全部楼层
2010.1.3

10.1从老家回来后折腾RC+比较器的ADC后的几周, 去中发进ADC0832两只, 终于不能忍受那个折磨, 不过玩吗,乐在其中. ADC0832, 8bit, 就是100%精准,也是只能探测到0.02V. 是不能满足-dV检测的, 不过学习下有必要阿.

搭建完成的面包板就是下面这一大陀东西. 乱阿, PCB果然有用哈.




----------------------------------------------------
r73 | heyongli | 2009-11-02 22:31:14 +0800 (一, 2009-11-02) | 2 行

电流采样运放电路仿真

------------------------------------------------------------------------
r72 | heyongli | 2009-11-01 19:57:36 +0800 (日, 2009-11-01) | 1 行

完善charger.c 接口,采用struct而不是全局变量
------------------------------------------------------------------------
r70 | heyongli | 2009-10-29 22:12:43 +0800 (四, 2009-10-29) | 7 行

1. 增加计时(纯粹计时不是充电计时)
2. 充电流程优化: 在涓充时至少会持续15秒,
3. 每个状态迁徙也至少4S(主要是fast/pre/trickle)以避免不断迁移

电池差基本就不能维持在快充状态, 最后在涓充状态. 好像有点自
适应能力,呵呵

------------------------------------------------------------------------
r69 | heyongli | 2009-10-28 22:54:57 +0800 (三, 2009-10-28) | 2 行

凑合能自动充电了, 电流测量
以及和pwm电路隔离还没有做好
------------------------------------------------------------------------
r68 | heyongli | 2009-10-25 23:26:55 +0800 (日, 2009-10-25) | 3 行

还是adc0832好用,简易ADC精度不好弄的.
驱动就是下面的一小段代码了.

#define CS     P3_0
#define CLK     P3_1
#define DI   P3_2
#define DO   P3_3

unsigned char adc0832(bit ch)
{
   unsigned char i, dat0=0, dat1=0;
   
   CLK = 0;   //init clk
   
   DO = 1;    //prepare start bit
   CS=0;       //enable  
   udelay(0); //delay tsu
   CLK = 1;   //up edge, send start bit
   udelay(0);

   CLK = 0;   //prepare send SGL/DIF
   udelay(0);
   DO = 1;    //SGL/DIF = 1, channel mode
   CLK =1;    // up edge, send SGL/DIF
   udelay(0);

   
   CLK=0;    // prepare send ODD/EVEN, ch
   udelay(0);
   DO = ch;      //send channel, 0,or 1
   CLK=1;     //up ledge;
   udelay(0);

   
   CLK=0;  //  
   DI=1;   //prepare input
   udelay(0); //delay tsu
   for(i=0;i<8;i++){
     CLK =1;
     udelay(0);         //没有这些delay则LSB,MSB方式读取的值会不等, 太快了
     CLK =0;  //donw edge /MSB first
     udelay(0);
     if(DI)
         dat0 |= 0x80>>i;   
   }

   for(i=0;i<8;i++){ //LSB first
     udelay(0);
     if(DI)
         dat1 |= 0x01<<i;   
      CLK =1;
      udelay(0);
      CLK =0;  //donw edge
      
   }
   CS=1;  //deselect chip
   DI=1;
   CLK=1;

   if(dat0==dat1) {
         return dat1;
    }
   return dat0;
}

出0入0汤圆

 楼主| 发表于 2010-1-3 19:03:55 | 显示全部楼层
2010.1.3

重新购得1602一个,花费16大元.从网上拽了代码下来, 果然能驱动哈. 好像没啥好摆活的. 贴上改过的驱动代码,保留原作者.




#define io_delay mdelay(8)
/***********************************************
程序名称:1602液晶显示程序
简要说明:使用MS1602液晶显示器,数据口接P0口,控制端接P2.0-P2.2
寄存器选择信号端RS-P2.0、读写信号端R/W-P2.1、使能信号端EP-P2.2
编    写:JiangX.net , hyl
***********************************************/
typedef unsigned char BYTE;
typedef unsigned int WORD;
typedef bit BOOL ;

sbit rs = P2^0;   //RS
sbit rw = P2^1;   //读写选择RW
sbit ep = P2^2;   //使能信号E

BYTE code dis1[] = {"Digital-Toy"};
BYTE code dis2[] = {"i-Charger V1.0"};


/*****判别LCD忙碌状态*****/
BOOL lcd_bz()
{
    BOOL result;
    rs = 0;
    rw = 1;
    ep = 1;
    result = (BOOL)(P0 & 0x80);
    ep = 0;
    return result;
}
/*****写入指令数据到LCD*****/
void lcd_wcmd(BYTE cmd)
{
  while(lcd_bz());
  rs = 0;
  rw = 0;
  ep = 0;
  udelay(100);
  P0 = cmd;

  ep = 1;
  ep = 0;   
}

/*****设定显示位置*****/
void lcd_start(BYTE start)
{        
   lcd_wcmd(start | 0x80);
}

/*****写入字符显示数据到LCD*****/
void lcd_data(BYTE dat)
{        
  while(lcd_bz());
  rs = 1;
  rw = 0;
  ep = 0;
  P0 = dat;
  ep = 1;
  ep = 0;
}

/*****LCD初始化设定*****/
void lcd_init()
{
    io_delay;      
    lcd_wcmd(0x38);    //设定LCD为16*2显示,5*7点阵,8位数据接口
    io_delay;
    lcd_wcmd(0x0c);    //开显示,不显示光标
    io_delay;
    lcd_wcmd(0x06);    //显示光标自动右移,整屏不移动
    io_delay;
    lcd_wcmd(0x01);    //显示清屏
    io_delay;

   
}


void lcd_logo()
{
  int pos=0,i=0;
  lcd_start(0);    // 设置显示位置为第一行的第5个字符
  io_delay;
  while(pos < (sizeof(dis1)-1)){
     lcd_data(dis1); // 显示第二行字符
     i++;pos++;
     io_delay;
  }   

  pos=0;i=0;
  lcd_start(0x40);   // 设置显示位置为第二行第一个字符
  while(pos<(sizeof(dis2)-1)){
     lcd_data(dis2); // 显示第二行字符
     i++;pos++;
     io_delay;
  }   


}

出0入0汤圆

 楼主| 发表于 2010-1-3 19:15:18 | 显示全部楼层
在上Meag8之前, 先看看ATtiny13吧. 引脚那个少, pwm/adc都不少. 用一路ADC 一路PWM, 3线驱动LCD,正好够用阿. 只是代码只有1k不够挥霍. 作为学习,当然要跑马灯:-)

网上拽下来的Attiny13的小玩意.


从这里开始, 打算把代码写的可复用程度高些, 多废代代码空间吧. 位操作, 前边已经发过帖子了.  学习用的attiny13 pwm:


/* bit ops*/
#define  _clear_bit(x,n)  x&=~(1<<(n))
#define  _set_bit(x,n)    x|= (1<<(n))
#define  _test_bit(x,n)  ( (x)&(1<<(n)))

/* mask ops */
#define _NM_MASK8(n,m)    (0xFF<<(n))&(0xFF>>(7-(m)))
                          /*n=2, m=3*/
                          /* xxxx XX00  &  0000 XXXX*/
#define  _clear_nm8(x,n,m)  x&= ~( _NM_MASK8(n,m))
#define  _nm8(val,n,m)      (val<<(n))&(_NM_MASK8(n,m))
#define  _set_nm8(x,val,n,m) _clear_nm8(x,n,m); \
                            x |= _nm8(val,n,m)

#include "bitops.h"
#include <avr/io.h>
#include <util/delay.h>
/*fast pwm mode*/
/*  9.6M  about 1000000/9.6M  104.17 ns*/
#define PWM_CYCLE  254


/* FAST PWM mode
The counter counts from BOTTOM to TOP then restarts from BOTTOM.  
---------------
TCCR0A :  COM0A1 COM0A0  

WGM2:0  
TOP is defined as 0xFF when WGM2:0 = 3  *
and OCR0A when WGM2:0 = 7

COM01 COM00:  
1       0     Clear OC0A on Compare Match, set OC0A at TOP *

------------------
TCCR0B :
WGM20   

CS02 CS01 CS00 :
0     1      0       clkI/O/8 (From prescaler)


------------------
TCNT0  -

OCR0A – Output Compare Register , cmpare to TCN0

GTCCR – General Timer/Counter Control Register
             Bit              7            0
                            TSM          PSR10      
             Read/Write     R/W           R/W
             Initial Value    0             0
            Bit 7 – TSM: Timer/Counter Synchronization Mode
            Writing the TSM bit to one activates the Timer/Counter Synchronization mode. In this mode, the
            value that is written to the PSR10 bit is kept, hence keeping the Prescaler Reset signal asserted.
            This ensures that the Timer/Counter is halted and can be configured without the risk of advanc-
            ing during configuration. When the TSM bit is written to zero, the PSR10 bit is cleared by
            hardware, and the Timer/Counter start counting.
            Bit 0 – PSR10: Prescaler Reset Timer/Counter0
            When this bit is one, the Timer/Counter0 prescaler will be Reset. This bit is normally cleared
            immediately by hardware, except ifexcept )

*/



void pwm_init()
{
  TCCR0A  =  ( _nm8(3,WGM00,WGM01) ) |  ( _nm8(0b10, COM0A0,COM0A1) );   
  TCCR0B  =  _nm8(0b001, CS00,CS02);      
  TCNT0  = 0;
  OCR0A = 0 ;  /* duty = 0; */

  GTCCR = 1; /*reset prescaler*/

}

void pwm_setduty(unsigned char duty)
{
  OCR0A = duty;
}



#define _key_init(x,n) DDR##x &= ~(1<< DD##x##n);  /*enable input*/   \
                       PORT##x |= (1<< P##x##n)    /*pull-up-enable*/   
#define _test_key(x,n)                                 \
        if( ! _test_bit(PIN##x, P##x##n) ){            \
            _delay_ms(7);                             \
            if(! _test_bit(PIN##x, P##x##n) )        \
                return 1;                            \
        }                                            \
       return 0                                        \


char keydown()
{
   _test_key(B,3);
}

出0入0汤圆

 楼主| 发表于 2010-1-3 19:47:02 | 显示全部楼层
(搞不定图片显示,不能自动缩小,影响观看....)
2010.1.3
看着这全部家当, 才能搞成一个charger,
终于不再能够忍受准备开始作成洞洞板模块吧.

准备图纸:

电流采样部分的仿真(不会计算):留有调整余量

开工:


Buck部分完成

<br>采样部分完成:


结束战斗了, 没有放电部分. 凑合用先. 加了一个光耦合, 必要的时候可以隔离.

出0入0汤圆

发表于 2010-1-3 19:58:07 | 显示全部楼层
顶,好复杂的样子

出0入0汤圆

发表于 2010-1-3 20:03:34 | 显示全部楼层
赞一个。

出0入0汤圆

 楼主| 发表于 2010-1-3 20:11:47 | 显示全部楼层
用面包板搭建Mega8电路, 下载器用杜邦线链接到DC10插座,就可以用usbasp 下载了. 两个按键,两个debug灯. 有1602的话,debug led就不要了.




ADC 代码
ADC 代码

/*
*  ADC1: the voltage of Battary,  50%  
*  ADC2: voltage of Battary,  1:1
*  ADC3: currrent sample
*/

void adc_init()
{
    short adc;

    /// AVCC, AREF 加滤波电容      ADCL keep low 8bit        init for ch0   
    ADMUX = _bits8(0b01,REFS0,REFS1) |   _bits8(0,ADLAR,ADLAR) |  _bits8(0,MUX0,MUX3);  
        /*must READ ADCH for compled ADC*/

    /*ADC status and control*/   
             /*enable ADC*/      /*start first ADC*/    /*no interrupt for now*/ /*4M/32, 125kHz*/
    ADCSRA = _bits8(1,ADEN,ADEN) | _bits8(1,ADSC,ADSC) |  _bits8(0, ADIE,ADIE)   | _bits8(0b101, ADPS0,ADPS2);
       /*wait for 25 ADC clock for first ADC completed*/
    while(!_test_bit(ADCSRA,ADIF));
    _set_bit(ADCSRA,ADIF); //clear IF bit
   
        adc = ADCL;
    barrier();
    adc = ADCH;
}



unsigned int _adc(unsigned char ch)
{
  unsigned int adc_l=0,adc=0;

  /*select channel*/
  _mov_bits8(ADMUX,ch,MUX0,MUX3,0,2); /*ADC0...ADC4*/

  /*start ADC*/
  _set_bit(ADCSRA,ADSC);

  /*wait completed(ADIF active)*/
   while(!_test_bit(ADCSRA,ADIF));

  /*read result */
  /*must READ ADCH for compled ADC*/
   adc_l = ADCL;
   /* GCC will swich ADCL read fist,so tell it don't do that*/
   barrier();
   adc =   ADCH ;
   adc = (adc<<8)|adc_l;

   _set_bit(ADCSRA,ADIF); //clear IF bit
   return adc;
}

PWM代码

/*channal A, TOP= ICR1, match:OCR1A, PWMhz= 15khz , fcpu=4Mhz*/
void pwm_init()
{

  TCCR1A  =   (_bits8(0b10,WGM10,WGM11) )  |  ( _bits8(0b10, COM1A0,COM1A1) );   
  TCCR1B  =   (_bits8(0b001, CS10,CS12))  | (_bits8(0b11,WGM12,WGM13));      
  TCNT1  = 0;
  ICR1 = 0xff ;  /* top = 0; */
   
  //only attiny13?  GTCCR = 1; /*reset prescaler*/
  _pin_mode(PORTB,1,OUTPUT);

}

void pwm_setduty(unsigned char duty)
{
  OCR1A = duty;
}

unsigned char pwm_getduty()
{
  return OCR1A;
}

出10入10汤圆

发表于 2010-1-3 20:40:49 | 显示全部楼层
不错!

出0入0汤圆

 楼主| 发表于 2010-1-3 20:51:31 | 显示全部楼层
Mega驱动1602的困境是引脚比较少, 所以,4线链接方式驱动1602势在必行. 只写,无法读取1602. 用延时代替busy检测. 电路如下:(http://www.ourdev.cn/attachment /app_1602B_lcd_using_sample_sch_1.jpg)


驱动问题

网上有很多驱动. 大多有一个问题:(ourdev当然有正确的,-:))
send_cmd(char data) : 发送8bit数据, 但是已经按照4线方式发送了. 这样初始化的时候 :
send_cmd(0x30);
send_cmd(0x30);
send_cmd(0x32);
工作就会不稳定, 时好时坏(因该是根本不成的). 原因是snd_cmd(0x30)的时候, 发送了一个0x30, 一个0x0, 而不是只发送了一次0x30.正确的初始化是:
  send_cmd(0x33);
  io_50ms();
  send_cmd(0x32);
  io_50ms();

  send_cmd(0x28); /* 4位数据线,5*10字体 */
  io_50ms();
完整驱动

可以同时支持4线直连到Mega(7根总共),或者通过hc595转接(3线驱动).

/*
* ref:
*     http://www.bpcd.net/teacher/electrical/web/PIC_MICRO.html
*  http://en.wikipedia.org/wiki/HD44780_Character_LCD
*
*  其他解决方案: MAXIM i2c 转HD44780 介绍
*  http://china.maxim-ic.com/app-notes/index.mvp/id/3658
*
* CopyLeft hyl 2009.12.19
*/

#include "include/avrio.h"
#include <util/delay.h>

#define USE_74HC595
//#undef  USE_74HC595

#define LCD_RSWE_PORT  PORTD  
#define LCD_DATA_PORT  PORTC   

#ifdef USE_74HC595   
  #define io_init() init_74hc595()
#else
  #define io_init() \
      _pins_mode(LCD_DATA_PORT,0,3,OUTPUT); \
      _pins_mode(LCD_RSWE_PORT,5,7,OUTPUT)
#endif

static char bus4w = 0;

#ifdef USE_74HC595   
#if 1
  static void _rswe(void )  
  {
  /*  |res| _RS| _RW | _EN | 4bit DATA | */
   /*    0    1    2     3     4  5 6  7  */
  /*         d7    d6   d5     d4 e rw rs*/
   #define m(d,s)   _mov_bits8(t,bus4w,d,d,s,s);
    /*100 bytes code*/
      char t=0;
      m(5,3); m(6,2);m(7,1);
      m(1,7); m(2,6);m(3,5);m(4,4);

      write_74hc595(t);
  }  
  #define  _data() _rswe()
#else
      #define  _rswe()  write_74hc595(bus4w)
      #define  _data()  write_74hc595(bus4w>>1)
#endif
#else
  #define  _rswe()  _mov_bits8(LCD_RSWE_PORT,bus4w,5,7,1,3)
  #define  _data()  _mov_bits8(LCD_DATA_PORT,bus4w,0,3,4,7);
#endif
/*************以下内容无需修改,移植请修改以上内容******************/

/*  74hc595 data format  
*  Ver0.1  
*  |res| _RS| _RW | _EN | 4bit DATA |
*    0    1    2     3     4 5 6 7  
*  4wire direct to IO
*  PORTD: 5    6     7  
*  PORTC:                  0 1 2 3  
*/
#define _RS          (1<<1)  
#define _RW          (1<<2)
#define _EN          (1<<3)  
#define _RSWE        (_RS|_RW|_EN)
#define _DATA        (0xf0)





/*************以下内容无需修改,移植请修改以上内容******************/

/*
#define  io_delay()  _delay_us(11);
    15us tested, 12us occation failed, 11us not stable, 10us failed
for safe and reserve space, use function and 12us   
*/
void io_delay()
{
   _delay_us(14);
}
void io_50ms()
{
   _delay_ms(50);
}

static void hd44870_send(unsigned char data, char is_cmd)  
{
  io_delay();
   
  bus4w &=~(_EN|_RW);        
  _rswe();
  //io_delay();
   
  if(is_cmd)
       bus4w&=~_RS;  //RS=0,command
  else
       bus4w|=_RS;  //RS=1, data
  _rswe();
  io_delay();
   
  /* 4 MSB*/
  bus4w &= ~(_DATA);     
  bus4w |= data&_DATA;  
  _data();
   
  io_delay();
  bus4w |=_EN;   
  _rswe();
  io_delay();  
  bus4w &=~_EN;   
  _rswe();

  io_delay();
   
  /*send low 4 lsb*/
  bus4w&=~_DATA;         
  bus4w|=(data<<4)&_DATA;  
  _data();
  io_delay();

  bus4w |=_EN;   
  _rswe();
  io_delay();  
  bus4w &=~_EN;   
  _rswe();
   
   
}

#define send_cmd(data) hd44870_send(data,1)
#define send_data(data) hd44870_send(data,0)

void lcd1602_init(void)     
{
  io_init();

  send_cmd(0x33);
  io_50ms();
  send_cmd(0x32);
  io_50ms();

  send_cmd(0x28); /* 4位数据线,5*10字体 */
  io_50ms();
   
  send_cmd(0x0c); /*开显示,无光标, 0xf:开光标并闪烁*/   
  io_50ms();

  send_cmd(0x06);  /* 光标自动右移,整屏不移动 */
  io_50ms();
   

  send_cmd(0x01);  /*清屏*/
  io_50ms();io_50ms();
}


void lcd_cursor(char x, char y)
{
    send_cmd(x+(y?0xc0:0x80));   
}

void lcd_puts(unsigned char *s)  
{
    while (*s)  
    {
      send_data( *s );
      s ++;
    }
      
}


char hex2c(char hex)
{

   if(hex<0xa)
      return '0'+hex;
   else
      return 'a'+hex-0xa;
}
void print10(unsigned short n)
{
     static char four[5];
     //irqoff();
     four[0]= hex2c( (n/1000) );
     n = n%1000;
     four[1]= hex2c(n/100);
     n = n%100;
               
     four[2]= hex2c( (n/10) );
     four[3]= hex2c( (n%10) );
     four[4]= 0;
     lcd_puts(four);
}



void lcd_putc(char data) //列x=0~15,行y=0,1
{
  send_data( data);
}

出0入0汤圆

 楼主| 发表于 2010-1-3 21:10:29 | 显示全部楼层
在下面两篇文章中,已经对hc595驱动1602调试过程中出现的问题做了一些详细的log. 这里补充成为完整的东西.一开始是面包板的版本,然后也弄了个洞洞版. 不堪回首哦.
劣质插座害死人
劣质插座害死人2

已经做了电源的防呆处理,用了XH2.54的插座供电.烧东西太快了.





74HC595 和 驱动电路

HC595电路链接方式我是参考这个改的了, 主要是左边是mega8, 右边是1602. 懒得画图. 要利用网络.

来源:http://www.gz112.cn/article/UploadPic/2008-1/2008114235844556.jpg

这里有个完整的:

来源:http://www.bpcd.net/teacher/electrical/web/labpic/lcd_with_74hc595.JPG

595的驱动代码


相关头文件下载:
头文件

#include <util/delay.h>
#include "include/avrio.h"


#define  PORT_74HC595   PORTD  
#define  CLK    5    /* raise-edge , shift clock: 74HC595 pin 11*/
#define  LATCH  6     /* raise-edge output to Qx, latch clock: 74HC595 pin 12*/
#define  SDI    7     /* CLK raise edge deposit, sserial data in: 74HC595 pin14*/


static void delay_io(void)
{
     /*asm("nop")*/ _delay_us(1);
}


void init_74hc595(void)  
{
    _pins_mode(PORT_74HC595, CLK,SDI,OUTPUT);
}  

void shiftout(unsigned char data)
{
    char i=0;
    for(i=0;i<8;i++){
       delay_io();
      
       if((data<<i)&0x80)
         _set_bit(PORT_74HC595, SDI);
       else
         _clear_bit(PORT_74HC595, SDI);

       delay_io();
      _set_bit(PORT_74HC595,CLK);  
       delay_io();
      _clear_bit(PORT_74HC595, CLK);
              
   }

}
void write_74hc595(unsigned char data)
{
    //_clear_bit(PORT_74HC595,CLK); //prepare send data
    delay_io();
      
    shiftout(data);
     
    delay_io();
    _set_bit(PORT_74HC595,LATCH); //prepare open latch
     delay_io();
     delay_io();
     delay_io();
    _clear_bit(PORT_74HC595,LATCH); //prepare open latch
   
}

出0入0汤圆

发表于 2010-1-6 09:47:31 | 显示全部楼层
这几天比较忙, 刚刚看到这个贴子.

非常支持楼主的动手精神, 终于感到一丝欣慰.

大家 DIY 的热情越来越高了.

出0入0汤圆

发表于 2010-1-6 10:16:23 | 显示全部楼层
哈哈~楼主真能折腾~

出0入0汤圆

发表于 2010-1-6 10:45:58 | 显示全部楼层
冲楼主这份执着的精神,一定要顶一下

出0入4汤圆

发表于 2010-1-6 10:48:42 | 显示全部楼层
顶,支持楼主的动手能力!

出0入0汤圆

 楼主| 发表于 2010-1-6 11:00:06 | 显示全部楼层
感谢各位,有人说话我很欣慰

出0入0汤圆

发表于 2010-1-6 11:21:03 | 显示全部楼层
顶,支持

出0入0汤圆

发表于 2010-1-6 11:35:51 | 显示全部楼层
LZ的帖子太牛了 呵呵
我好好学习 谢谢了 呵呵

ps:动手能力好强啊

出0入8汤圆

发表于 2010-1-6 13:31:24 | 显示全部楼层
不错。DIY玩得就是这个精神。

出0入0汤圆

发表于 2010-1-13 12:38:38 | 显示全部楼层
乐在其中,好玩家啊,呵呵,学习了

出0入0汤圆

发表于 2010-1-14 14:02:22 | 显示全部楼层
太强了,顶一下。

出0入0汤圆

发表于 2010-1-22 17:38:49 | 显示全部楼层
支持楼主的的精神

出0入0汤圆

发表于 2010-1-22 18:16:16 | 显示全部楼层
万用板不错

出0入0汤圆

发表于 2010-4-23 15:14:11 | 显示全部楼层
精神可嘉   支持

出0入0汤圆

发表于 2010-4-23 15:45:34 | 显示全部楼层
真能折腾!佩服!!

出0入0汤圆

发表于 2010-4-23 15:53:32 | 显示全部楼层
动手能力强悍

出0入0汤圆

发表于 2010-4-23 19:15:00 | 显示全部楼层
lz相当的diy啊

出0入0汤圆

发表于 2010-5-1 21:45:08 | 显示全部楼层
好帖,那个mos管换为普通三极管可以?

出0入0汤圆

发表于 2010-5-1 22:03:28 | 显示全部楼层
LZ以折腾为乐趣啊

出0入0汤圆

发表于 2011-12-9 16:57:54 | 显示全部楼层
佩服,自叹不如啊!

出0入0汤圆

发表于 2011-12-9 17:22:36 | 显示全部楼层
顶楼主的热情似火。
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-3-29 23:45

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表