一个数字直流电源--第二部分:软件

ArticleCategory: [Choose a category, do not translate this]

Hardware

AuthorImage:[Here we need a little image from you]

[Photo of the Author]

TranslationInfo:[Author + translation history. mailto: or http://homepage]

original in en Guido Socher

en to zh_CN SEVEN

AboutTheAuthor:[A small biography about the author]

Guido喜欢LINUX,因为对于开发自己的硬件来说,它确实是一个很好的系统。

Abstract:[Here you write a little summary]

这是有关数字电源系列的第二部分。你可能希望先阅读本系列的第一部分。

我可能会增加第三部分——增加i2c通信以从PC通过命令控制电源。 也可能还会有第四部分——增加一些更有趣的东西。 我在考虑除了直流电压,还可以让它输出直流脉冲和尖峰脉冲, 这样你就可以通过测试电路来保证它们能抵抗电源噪声和振荡。 包含电路板和所有零件的一个工具箱可以从shop.tuxgraphics.org获得。

ArticleIllustration:[This is the title picture for your article]

[Illustration]

ArticleBody:[The article body]

简介

我们可以通过使用一个基于聪明的微控制器的设计, 来制作一个比传统电源更便宜且有更多特性的电源。 这是可能的,因为以前使用硬件来实现的功能在这里我们都使用软件来实现。

在这篇文章中我们要做两件事情:

一点警告

这篇文章会告诉你软件是如何工作的,你可以使用从这里所学的知识来做一些修改。 但你要明白短路保护也只是在软件中实现的,如果某些地方有错误, 这种保护可能不能正常工作。如果在输出中导致短路, 你的硬件可能会在一缕青烟中化为灰烬。为了防止这种情况出现, 你可以使用一个大电阻(例如一个汽车前灯的灯泡), 它可以拉动足够的电流来激活保护而使硬件免于损坏。 这样你就可以测试短路而没有失去硬件的危险。

软件的结构

你在main程序中(ddcp.c文件,本文最后有下载)只能看到几行在加电时初始化的代码, 然后软件会进入一个无限循环。
在该软件中有两处无限循环:第一个在main循环中(ddcp.c中的“while(1){ ...}”), 第二个在模数转换器的周期性的中断中(analog.c中函数“SIGNAL(SIG_ADC){...}”)。 系统初始化时设置为每100μ秒发生一次中断。 所有的函数和代码在其中一个任务(任务是在一个实时操作系统中执行的一个进程或线程的名字, 所以,即使没有操作系统,我也这样称呼它)的上下文环境中执行。
[priorities]

中断任务可以在任何时候停止main循环的执行而执行它自己的代码, 并且中断任务的执行是不会被中断的。当中断任务执行完毕时, main循环会从中断处接着执行。这样会有两种后果:
  1. 由于中断代码的执行要在下一次中断到来之前结束,所在它不能太长。 这里要计算的是机器代码指令的数量。 一个可以仅用一行C代码写成的数学公式可能会产生数百行的机器代码。

  2. 在中断代码和main程序代码中共享的变量可能会在执行过程中突然改变。 当你从中断向main程序中传递多于一个字节的数据时这是合法的。 拷贝两个字节需要不止一条指令,那么就可能会出现一个字节在中断之前被拷贝, 而另一个字节却在中断之后。怎么办呢?由于ADC测量的结果在两次中断之间不会相差很大, 这在大多数情况下不会有什么问题。 万一你不能忍受这种偶然性的错误(每小时可能只发生一次), 你就必须使用一个标志位,通过它可以检查你的代码是否在拷贝过程中被中断了。
所有这些意味着一些复杂的事情如刷新显示屏、检测按钮、 将安培和伏特值转换为内部单位等等都需要在main程序中完成。 在中断过程中我们只做时间紧迫的事:电流电压控制、过压保护和设置DAC。 为了避免复杂的数学运算,所有的计算都在ADC单元中完成(跟ADC产生的单元相同,值从0到1023)。

下面是main程序中确切的逻辑流程:
1) 从中断任务中拷贝最后的ADC结果
2) 将它们转换为显示值(安培或伏特)
3) 将想要的安培或伏特值(用户设定的)转换成内部的等效ADC值
4) 将想要的等效ADC值拷贝到一个变量(比方说一个中断任务可以使用的变量)
5) 清LCD显示屏
6) 将我们要在LCD上显示的数字转换成字符串
7) 在显示屏上显示电压值
8) 检查中断任务是否可以调节电压或电流(电流限制激活)
9) 如果电压是限制因子,那么在电压值后面显示一个箭头
10)把安培值写到显示屏上
11)检查中断任务是否可以调节电压或电流(电流限制激活)
12)如果电流是限制因子,那么在电流值后显示一个箭头
13)检查是否有按钮被按下,如果没有等待100毫秒再检查。如果有按钮按下,
	那么等待200毫秒,这是为了有一个好的响应——如果按钮被持续按住时不致于滚动过快。
14)回到第一步。
中断任务简单得多:
1) 将ADC结果拷贝到变量
2) 在电流和电压间切换ADC测量通道
3) 检查是否测量到过流,若过流则立即将DAC设为一个很小的值(不必为0,
   因为电压放大器只工作在0.6V以上(0.6V的输入仍得到0V的输出))。
4) 检查电压电流是否需要调节
5) 根据4)的结果检查是否需要更新DAC(数模转换器)


这是软件基本的思想,下面我将解释一下它们都在哪些文件中, 然后你将明白这些代码(假设你熟悉C语言)。

各文件中都包含什么

ddcp.c -- 该文件包含main程序。所有初始化工作都在此完成。main循环也在这里实现。
analog.c -- 模数转换器以及所有在中断任务相关上下文中执行的代码都可以在此找到。
dac.c -- 数模转换器,在ddcp.c中初始化,但只在analog.c中调用。
kbd.c -- 键盘代码。
lcd.c -- LCD驱动。这一专门的版本不需要LCD的rw针脚,而使用一个内部定时器,
         它应该能有足够长的时间来完成中断任务。

新功能:保存配置数据

本文中的新功能不是很多,因为我已经用了大量的篇幅来解释软件是怎么工作的, 而我不想让这篇文章太长。

但我们所加的这项功能是非常重要的:将电压或电流值保存下来, 我们就不用在下次加电时重新设置了。我们将这些值存储在微控制器的eeprom中。 所有的eeprom(包括usb存储器)中存储单元的写次数都是有限的。 对于Atmega8来说是100000次,之后eeprom就会失效而不能再存储数据了。 延长eeprom使用寿命的一个小技巧就是每次将数值写到不同的单元里, 但这需要首先计算存储单元的地址。如果每天存储10次配置数据, 100000次写操作意味着可以使用25年,对我们来说绝对是足够了。 所以我们使用最简单的方案:只将数据存储到一个地方。

那么如何在eeprom中读写数据呢?有两条指令:eeprom_read_word和 eeprom_write_word可以从/向eeprom中读写16比特的整数。eeprom 的地址从0开始,并以字节计数。

复杂的一点的地方是每次我们更新软件时,eeprom内容都会被删除。 所以我们需要知道我们是否从eeprom中读到了垃圾数据(因为刚写进了新的软件) 或者说是否我们在eeprom中存储了合法的电压电流值。 我们通过在eeprom中写入一个魔数(magic munber)来做这件事。 换句话说,每次我们都写入3个值:电流极限值、电压极限值和魔数。 加电后读eeprom时,我们首先检查这个魔数,如果匹配, 我们就认为我们所存储的电压和电流值是正确的。 该魔数可以是任意值(比方说19),只要不是eeprom中的缺省值就可以了。

代码请看ddcp.c中的store_permanent()函数。

本文的软件是digitaldcpower-0.3.X,其中X是修正的版本。 以后若需要更新我会继续修改该X值(上一篇文的软件是digitaldcpower-0.2.X)

玩的开心!……下一篇文中我将增加PC到电源的I2C通信, 届时你就可以通过命令而不仅仅是电源上的按钮来改变一些相关的东西了。

希望有人能将I2C主机程序移植到其它的操作系统上。如果你能帮上忙的话请通知我。 你需要有如何控制RS232接口的知识以及一个编译器。 实际上也许只是需要改变一行代码就可以了(ioctl函数)。

整个电路包括所有的零件和一个印刷电路板可以从shop.tuxgraphics.org获得(见下文)。

参考资料/下载