转载----用指针式电压表制作超 · 极客时钟!《无线电》杂志 公众号
本帖最后由 八兆天空 于 2017-2-8 16:41 编辑转载于 《无线电》公众号
无线电杂志微信号 radiomagazine
看到标题,可能很多朋友已经按捺不住自己了!没错!就是这种非常硬核的极客风格,今天来学习一下如何使用指针式的电压表来作为指针,显示当前的时间和温度吧!
实际上,这个设计原理非常好懂:单片机使用PWM并通过电阻分压来得到0~2V的电压值,而这个电压则是表头的满偏电压,而将其分成60份后,就可以用来指示60分钟或60秒的示数了。时间采用实时时钟DC1307来保存,而温度则通过读写单线温度传感器DS18B20得到。整个设计的主控单片机使用Picaxe 14M2单片机。不过说实话,这个单片机使用什么都无所谓,只要能够有三路PWM输出(或软或硬)即可。
原理非常简单,可能最难的地方在于如何分出适当的电压值。将2V分成60份,每份电压值为0.033V,因此表盘的设计和电压的输出就全都要参照这个电压值来设计。每增加一个分度,PWM都要相应地增加0.033V的电压值,而这又要考虑到PWM的精度和外部的低通滤波电路。因此这个设计还需要一定的思考才行!
其他的诸如操作DC1307和DS18B20的程序我想大家已经非常熟悉了,此处不再赘述。如果想要借鉴源程序的话欢迎在公众号的对话中回复“电压表时钟”以取得源程序哦!
本文为 无线电杂志 微信公众平台原创文章。详细内容及高清大图请查阅《无线电》杂志。版权所有,欢迎个人转发至朋友圈。公众号、报刊等转载请给本公众号后台留言获得授权。
…………………………………………………
无线电杂志
微信号:radiomagazine长按识别二维码关注我们
电压表时钟 · 源程序
2017-01-16 WTH 无线电杂志
电压表时钟的正文,请看一楼
;源程序由WTH编写,运行于PicAxe
14M2上,阅读程序可以让你了解思
路。
; Project Name: 3 Panel Meter Clock
; REV: FIN (everything works fine with
clock and temp)
;
; Start Date:Feb 12, 2012
;
; Program Rev History/Ideas:
; - to set clock push M or H button
; - push main button to display temp
F, C, and K
; - Routine to drive 3 meters to full
scale when main button AND (M OR
H)
; is pressed.This is to allow
adjustment of trimmers to full scale.
; Adjustment to zero scale should be
done first with power off.
;
; *******************************
; PICAXE PE Rev: MacAXEPad 1.3.2
;
#picaxe14m2
'define memory locations as symbols
symbol hour_meter = c.0 'LEG 7
symbol minute_meter = c.2 'LEG 5
symbol second_meter = b.2 ' LEG 11
symbol temp_switch = pinc.4 ' LEG3
symbol temp_sensor = b.5 'LEG8
symbol hour_set = pinc.3 'LEG3
symbol minute_set = pinc.1 'LEG6
symbol CthermoValue = b10
symbol FthermoValue = b11
symbol KthermoValue = w6 'b12 and
b13
symbol seconds = b0
symbol minutes = b1
symbol hours = b2
symbol day = b3
symbol date = b4
symbol month = b5
symbol year = b6
symbol blinky = b7
symbol Tens_Digi = b8 ;Used to get
the Tens Digit from the $HEX RTC
value
symbol Ones_Digi = b9 ;Used to get
the Ones Digit from the $HEX RTC
value
' w7 (b14 and b15) is used to control
the PCM to the meters
' Set the time on the DS1307 RTC
i2cslave %11010000, i2cslow, i2cbyte ;
set PICAXE as master and DS1307
slave address
pause 50
'Set all meters to full scale with 100%
duty cycle
pwmout hour_meter,99,400
pwmout minute_meter,99,400
pwmout second_meter,99,400
'\/ \/ \/ \/ Un_REM THESE LINES
(BELOW) IF SETTING UP A NEW RTC\/
\/ \/ \/
#rem
' Set the RTC chip time
;write time and date e.g. to 11:59:00
on Thurs 25/12/03
'; would be "writei2c 0,($00, $59, $11,
$03, $25, $12, $03, 010000)"
' readi2c 0, (b0,b1,b2,b3,b4,b5,b6,b7)
reads back the data
let seconds = $00 ; 00-59 Note all
BCD format
let minutes = $00 ; 00-59 Note all
BCD format
let hours = $01 ; 01-12 Note all BCD
format
let day = $03 ; program does not
use date, date, month, year
let date = $22
let month = $03
let year = $12
let blinky = 000000 ; 010000 would
Enable output at 1Hz blink rate.
000000 is no blink
writei2c 0,(seconds, minutes, hours,
day, date, month, year, blinky)
pause 50
#endrem
'/\ /\ /\ /\ Un_REM THESE LINES
(ABOVE) IF SETTING UP A NEW RTC/\
/\ /\ /\
; POWER ON SELF TEST.Send all three
meters to FULL Scale and back to 0
'NOTE:pwmduty hour_meter, w7
---->> w7 ranges from 0 to 400 to
move meter from 0VDC to 2VDC
for w7 = 400 to 0 step -1' pwmduty
needs a (W)ord var, not a (B)yte var
pwmduty hour_meter, w7 'adjust
PWM Duty from 100% to 0%
pwmduty minute_meter, w7
pwmduty second_meter, w7
next w7
main:
if temp_switch = 1 then
do ' while hour_set = 1 or minute_set
= 1 then 'if main buttom and H or M
set button pushed then
pwmduty hour_meter, 400 ' move all
meters to full scale to allow trimmer
adjust.Do 0 meter adjust1st with
power off.
pwmduty minute_meter, 400
pwmduty second_meter, 400
loop while hour_set = 1 or minute_set
= 1
end if ' temp_switch = 1
if temp_switch = 1 and hour_set = 0
and minute_set = 0 then
do 'while temp_switch is pressed
gosub DisplayTemp
loop while temp_switch = 1 and
hour_set = 0 and minute_set = 0
end if
'read the RTC and display the time
readi2c 0, (seconds, minutes, hours,
day, date, month, year, blinky)
pause 10
'\/ \/ \/ \/ \/ SECONDS SECONDS
SECONDS \/ \/ \/ \/ \/
;Convert the Seconds from the RTC to
Base10 and update the meter
if temp_switch = 0 and minute_set =
1 and hour_set = 1 then 'all pressed.
Seconds to $00
gosub Seconds_set
end if
Ones_digi = seconds & 0x0F ' zero
out the top four bits
Tens_Digi = seconds & 0xF0 ' zero
out the lower four bits
Tens_Digi = Tens_Digi / 2 ' each
divide by 2 shifts the
Tens_Digi = Tens_Digi / 2 ' bits LEFT.
Four shift get
Tens_Digi = Tens_Digi / 2 ' them all to
the lower four bits
Tens_Digi = Tens_Digi / 2
Tens_Digi = Tens_Digi * 10 'Now shift
the Base10 value to Tens place
seconds = Tens_Digi + Ones_Digi
'complete. Now $ss is ss (in Base10)
' Update the seconds meter with a
w9 value of 0 to 400
w7 =seconds * 677 / 100;
(400/59=6.77) scale 0-59 seconds to
0-400 for PWM
pwmduty second_meter, w7
'/\ /\ /\ /\ SECONDS END /\ /\ /\ /\
/\ /\ /\
'\/ \/ \/ \/ MINUTES MINUTES
MINUTES \/ \/ \/ \/ \/
if temp_switch = 0 and minute_set =
1 and hour_set = 0 then 'if
temp_switch and M is pressed then
add on minute
gosub Minutes_set
end if
;Convert the Minutes from the RTC to
Base10 and update the meter
Ones_digi = minutes & 0x0F ' zero
out the top four bits
Tens_digi = minutes & 0xF0 ' zero
out the lower four bits
Tens_Digi = Tens_Digi / 2 ' each
divide by 2 shifts the
Tens_Digi = Tens_Digi / 2 ' bits LEFT.
Four shift get
Tens_Digi = Tens_Digi / 2 ' them all to
the lower four bits
Tens_Digi = Tens_Digi / 2
Tens_Digi = Tens_Digi * 10 'Now shift
the Base10 value to Tens place
minutes = Tens_Digi + Ones_Digi
'complete. Now $mm is mm (in
Base10)
'Update the minutes meter with a w9
value of 0 to 400
If minute_set = 0 then 'dont update if
we are setting the minutes.Should
correct this in Minutes_set routine
w7 = minutes * 677 / 100 ;
(400/59=6.77) scale 0-59 minutes to
0-400 for PWM
pwmduty minute_meter, w7
end if
'/\ /\ /\ /\ /\ MINUTES END /\ /\ /\ /\
/\
'\/ \/ \/ \/ \/ HOURS HOURS HOURS
\/ \/ \/ \/
if temp_switch = 0 and minute_set =
0 and hour_set = 1 then 'if
temp_switch and M is pressed then
add on minute
gosub Hours_set
end if
;Convert the Hours from the RTC to
Base10 and update the meter
Ones_digi = hours & 0x0F ' zero out
the top four bits
Tens_digi = hours & 0xF0 ' zero out
the lower four bits
Tens_Digi = Tens_Digi / 2 ' each
divide by 2 shifts the
Tens_Digi = Tens_Digi / 2 ' bits LEFT.
Four shift get
Tens_Digi = Tens_Digi / 2 ' them all to
the lower four bits
Tens_Digi = Tens_Digi / 2
Tens_Digi = Tens_Digi * 10 'Now shift
the Base10 value to Tens place
hours = Tens_Digi + Ones_Digi
'complete. Now $hh is hh (in Base10)
if hours > 12 then
hours = hours - 12
end if
if hours = 0 then
hours = 12
end if
' Update the hours meter with a w9
value of 0 to 400
w7 = hours * 3636; (400/11 = 36.36)
scale 1 to 12 hours to 0-400 for PWM
w7 = w7 - 3636 'subtracty interceot
to start PCM at 0 to 1 o'clock.
w7 = w7 / 100 'scale 1 to 12 hours to
0-400 for PWM
pwmduty hour_meter, w7
'/\ /\ /\ /\ /\ HOURS END /\ /\ /\ /\
/\
goto main
DisplayTemp:
readtemp temp_sensor,
CthermoValue
w7 = CthermoValue * 677 / 100
'(400/59=6.77) scale C to 0-400 for
PWM
pwmduty minute_meter, w7 'C (raw)
in the minutes meter)
'Convert C to F
FthermoValue = 9 * CthermoValue / 5
+ 32
w7 = FthermoValue * 364; (400/11 =
36.36)scale 10 to 120Fto 0-400 for
PWM
w7 = w7 - 3636 'subtracty interceot
to start PCM at 0 to 10F
w7 = w7 / 100 'scale 0-400 for PWM
pwmduty hour_meter, w7 '(F (x10) on
the hours meter
'Convert C to K
KthermoValue = CthermoValue + 273
w7 = KthermoValue / 10
w7 = w7 * 677 / 100
pwmduty second_meter, w7 'Kelvin
*100 on the seconds meter
return 'DisplayTemp
Seconds_Set:
seconds = $00
writei2c 0,(seconds, minutes, hours,
day, date, month, year, blinky)
pause 50
w7 =seconds * 677 / 100;
(400/59=6.77) scale 0-59 seconds to
0-400 for PWM
pwmduty second_meter, w7
return 'Seconds_set
Minutes_Set:
readi2c 0, (seconds, minutes, hours,
day, date, month, year, blinky)
;Convert the Minutes from the RTC to
Base10 and update the meter
Ones_digi = minutes & 0x0F ' zero
out the top four bits
Tens_digi = minutes & 0xF0 ' zero
out the lower four bits
Tens_Digi = Tens_Digi / 2 ' each
divide by 2 shifts the
Tens_Digi = Tens_Digi / 2 ' bits LEFT.
Four shift get
Tens_Digi = Tens_Digi / 2 ' them all to
the lower four bits
Tens_Digi = Tens_Digi / 2
Tens_Digi = Tens_Digi * 10 'Now shift
the Base10 value to Tens place
minutes = Tens_Digi + Ones_Digi
'complete. Now $mm is mm (in
Base10)
minutes = minutes + 1
if minutes > 59 then
minutes = 0
end if
'convert base10 minutes to BCD here
then write new minute value to RTC
Ones_Digi = minutes // 10
Tens_Digi = minutes - Ones_Digi
Tens_Digi = Tens_Digi / 10
Tens_Digi = Tens_Digi * 2' shift the
lower right bits
Tens_Digi = Tens_Digi * 2' to the
upper left.
Tens_Digi = Tens_Digi * 2
Tens_Digi = Tens_Digi * 2
Tens_Digi = Tens_Digi OR Ones_Digi
'OR function on the two values to get
8 bit BDC
'Now Ten_digi = minutes in packed
BCD.Just using Tens_Digi as a temp
var
writei2c 0,(seconds, Tens_Digi, hours,
day, date, month, year, blinky)
pause 50
'Update the minutes meter with a w9
value of 0 to 400
w7 = minutes * 677 / 100 ;
(400/59=6.77) scale 0-59 minutes to
0-400 for PWM
pwmduty minute_meter, w7
pause 500
return ' Minutes_Set
Hours_Set: 'HOURS SET WORKS
PERFECT
readi2c 0, (seconds, minutes, hours,
day, date, month, year, blinky)
;Convert the Hours from the RTC to
Base10 and update the meter
Ones_digi = hours & 0x0F ' zero out
the top four bits
Tens_digi = hours & 0xF0 ' zero out
the lower four bits
Tens_Digi = Tens_Digi / 2 ' each
divide by 2 shifts the
Tens_Digi = Tens_Digi / 2 ' bits LEFT.
Four shift get
Tens_Digi = Tens_Digi / 2 ' them all to
the lower four bits
Tens_Digi = Tens_Digi / 2
Tens_Digi = Tens_Digi * 10 'Now shift
the Base10 value to Tens place
hours = Tens_Digi + Ones_Digi
'complete. Now $hh is hh (in Base10)
hours = hours + 1
if hours > 12 then
hours = hours - 12
end if
if hours = 0 then
hours = 12
end if
if hours > 9 then
if hours = 10 then
hours = $10
end if
if hours = 11 then
hours = $11
end if
if hours = 12 then
hours = $12
end if
end if
writei2c 0,(seconds, minutes, hours,
day, date, month, year, blinky)
pause 50
;Convert the Hours from the RTC to
Base10 and update the meter
Ones_digi = hours & 0x0F ' zero out
the top four bits
Tens_digi = hours & 0xF0 ' zero out
the lower four bits
Tens_Digi = Tens_Digi / 2 ' each
divide by 2 shifts the
Tens_Digi = Tens_Digi / 2 ' bits LEFT.
Four shift get
Tens_Digi = Tens_Digi / 2 ' them all to
the lower four bits
Tens_Digi = Tens_Digi / 2
Tens_Digi = Tens_Digi * 10 'Now shift
the Base10 value to Tens place
hours = Tens_Digi + Ones_Digi
'complete. Now $hh is hh (in Base10)
' Update the hours meter with a w9
value of 0 to 400
w7 = hours * 3636; (400/11 = 36.36)
scale 1 to 12 hours to 0-400 for PWM
w7 = w7 - 3636 'subtracty interceot
to start PCM at 0 to 1 o'clock.
w7 = w7 / 100 'scale 1 to 12 hours to
0-400 for PWM
pwmduty hour_meter, w7
pause 1000
return ' Hours_Set 好思路.
用4个或者5个表头, 每个表头只要能显示0-9这几个数值, 就可以让指针万用表具备与4位或者5位数码管显示的万用表相同的分辨率了. 作者 大才小用 能有这样的技术 我就去 做表头 和家用定时器不过作者可能是都会 了才做些与众不同的东西:lol 这是就是炫一下,没有什么实际效用,首先就是读数不明显 眉间尺 发表于 2017-2-8 17:17
好思路.
用4个或者5个表头, 每个表头只要能显示0-9这几个数值, 就可以让指针万用表具备与4位或者5位数码 ...
每个表盘100刻度,视觉可直读两位数。两个表盘四位数,最大是9999,比三位半还强。
不过看完第一表盘,记住读数,再看第二表盘的读数,合拢起来才是结果,会很不方便,怪怪的,拿来玩可以。 没有数码管的时代,就是用这个办法显示数字电路的输出的,按数字电路的权值取电阻就可以显示一位数字信息。 老柳 发表于 2017-3-22 13:33
每个表盘100刻度,视觉可直读两位数。两个表盘四位数,最大是9999,比三位半还强。
不过看完第一表盘, ...
看数码管如果看了个位忘了十位或者百位也不行啊.:lol 学习看看听很高级 不错的作品!
单片机,不懂。想学,老了,太迟了。 不知道源程序是用什么语言写的。 独特风格 学习一下 换三个猫头表加黄色背光更赞