之前曾以四個七段顯示器製作時鐘,這篇則是介紹四合一的七段顯示器,目標是讓它從0000開始計數,然後每秒加1,0001、0002、0003、依此類推。
電路圖與原始碼可到GitHub下載,按「Download ZIP」即可全部下載,本篇程式碼位於子目錄SevenSegment4in1內。
底下是我買的共陰極、四合一型七段顯示器,每個七段顯示器含小數點。
底下是腳位圖,共有12個腳位,其中8個的功能就是控制七段顯示器,另4個腳位則代表想要控制哪一個七段顯示器,當腳位0為LOW、而腳位1、2、3為HIGH時,代表想要控制最右邊的七段顯示器,依此類推。
控制七段顯示器的8個腳位,a、b、c、d、e、f、g、h(dp),如下所示,本篇不使用h(dp)小數點。
因為有4個七段顯示器,我們必須使用掃描的方式不斷地顯示每一個七段顯示器,只要掃描速度夠快,基於視覺暫留原理,人眼便無法察覺,以為所有數字皆為同時顯示。
電路圖,沒什麼特別的,順著接即可,將在程式碼裡定義腳位的功能。
Arduino數位腳位2接到顯示器的0,
Arduino數位腳位3接到顯示器的g,
Arduino數位腳位4接到顯示器的c,
Arduino數位腳位5接到顯示器的h,
Arduino數位腳位6接到顯示器的d,
Arduino數位腳位7接到顯示器的e,
Arduino數位腳位8接到顯示器的b,
Arduino數位腳位9接到顯示器的1,
Arduino數位腳位10接到顯示器的2,
Arduino數位腳位11接到顯示器的f,
Arduino數位腳位12接到顯示器的a,
Arduino數位腳位13接到顯示器的3。
在下圖裡的四合一型七段顯示器擁有16個針腳,因為我找不到12個針腳的。
照理說,應該要串聯電阻220歐姆,不過我沒加也沒事orz。另外有些文章說Arduino輸出的電流不夠無法驅動,需加入NPN電晶體,不過我沒用也ok。
底下是程式碼:
// 定義腳位
#define PIN_0 2
#define PIN_g 3
#define PIN_c 4
#define PIN_h 5
#define PIN_d 6
#define PIN_e 7
#define PIN_b 8
#define PIN_1 9
#define PIN_2 10
#define PIN_f 11
#define PIN_a 12
#define PIN_3 13
// 共有4個七段顯示器,分別由針腳PIN_0、PIN_1、PIN_2、PIN_3控制
// 七段顯示器裡有8個LED(包含小數點)
#define POS_NUM 4
#define SEG_NUM 8
const byte pos_pins[POS_NUM] = {PIN_0, PIN_1, PIN_2, PIN_3};
const byte seg_pins[SEG_NUM] = {PIN_a, PIN_b, PIN_c, PIN_d, PIN_e, PIN_f, PIN_g, PIN_h};
// 底下定義由七段顯示器顯示數字時所需要的資料
#define t true
#define f false
const boolean data[10][SEG_NUM] = {
{t, t, t, t, t, t, f, f}, // 0
{f, t, t, f, f, f, f, f}, // 1
{t, t, f, t, t, f, t, f}, // 2
{t, t, t, t, f, f, t, f}, // 3
{f, t, t, f, f, t, t, f}, // 4
{t, f, t, t, f, t, t, f}, // 5
{t, f, t, t, t, t, t, f}, // 6
{t, t, t, f, f, f, f, f}, // 7
{t, t, t, t, t, t, t, f}, // 8
{t, t, t, t, f, t, t, f}, // 9
};
// 一支方便的函式,以格式字串輸出到序列埠
void pf(const char *fmt, ... ){
char tmp[128]; // max is 128 chars
va_list args;
va_start (args, fmt );
vsnprintf(tmp, 128, fmt, args);
va_end (args);
Serial.print(tmp);
}
// 設定某個七段顯示器所顯示的數字,
// 參數pos為0~3,指出想要更新哪一個七段顯示器,
// 參數n為0~9,顯示數字
void setDigit(int pos, int n){
if(pos < 0 || 3 < pos){
pf("error pos=%d\n", pos);
return;
}
// 控制想要更新哪一個七段顯示器,將其腳位設為LOW
// 其他腳位則設為HIGH,代表不更新。
for(int p = 0; p < POS_NUM; p++){
if(p == pos)
digitalWrite(pos_pins[p], LOW);
else
digitalWrite(pos_pins[p], HIGH);
}
// 寫入數字
if(0 <= n && n <= 9){
for(int i = 0; i < SEG_NUM; i++){
digitalWrite(seg_pins[i], data[n][i] == t ? HIGH : LOW);
}
}
else{
for(int i = 0; i < SEG_NUM; i++){
digitalWrite(seg_pins[i], LOW);
}
digitalWrite(PIN_h, HIGH);
pf("error pos=%d, n=%d\n", pos, n);
}
}
// 設定整個四合一型七段顯示器想要顯示的數字
// 參數number的範圍應是0~9999
void setNumber(int number)
{
int n0, n1, n2, n3;
n3 = number / 1000;
number %= 1000;
n2 = number / 100;
number %= 100;
n1 = number / 10;
n0 = number % 10;
// 求出每個位數的值後,分別更新
// 注意,此處以delay(5)隔開每個位數的更新
setDigit(0, n0); delay(5);
setDigit(1, n1); delay(5);
setDigit(2, n2); delay(5);
setDigit(3, n3); delay(5);
}
unsigned long time_previous;
void setup() {
Serial.begin(115200);
for(int i = 0; i < POS_NUM; i++){
pinMode(pos_pins[i], OUTPUT);
digitalWrite(pos_pins[i], HIGH);
}
for(int i = 0; i < SEG_NUM; i++){
pinMode(seg_pins[i], OUTPUT);
digitalWrite(seg_pins[i], LOW);
}
time_previous = millis();
}
int number = 0;
void loop() {
// 經過一秒後就讓number加1
unsigned long time_now = millis();
if(time_now - time_previous > 1000){
number++;
time_previous += 1000;
pf("number=%d\n", number);
}
// 不斷地寫入數字
setNumber(number);
}
成功的話,一開始會顯示0000,然後是0001、0002、0003、等等。
可修改的地方:
- 可使用4511減少腳位數量,但4511只能搭配共陰極七段顯示器。
- 處理大於9999的情況。
- 修改setNumber函式裡delay(5)的延遲值,改成10或50,試試看有何效果。
- Cooper Maa的Arduino 筆記 – Lab15 使用四位數七段顯示器製作計數器。
- CD4511與7段顯示器的應用 (一)。
呵~~~我同你一樣不信邪,
ReplyDelete突然有天 7 SEG.就不亮了,
後來我都乖乖加電阻.
嗯,說的對。
Delete我想把DS18B20的程式http://yehnan.blogspot.tw/2013/01/arduinods18b20.html跟這個4合一七段的程式合併
ReplyDelete顯示感測的數值在七段上 可是我做到最後可以顯示溫度了 但是百.十.個位數會一直閃
加了這行之後就會開始一直閃sensors.requestTemperatures(); 就會開始一直閃
可以教我一下如何合併嗎 ??
你的程式碼?
Delete小弟我剛學 亂湊湊出來了 你幫我看看
ReplyDelete// 匯入程式庫標頭檔
#include
#include
// Arduino數位腳位22接到1-Wire裝置
#define ONE_WIRE_BUS 22
// 運用程式庫建立物件
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
// 定義腳位
#define PIN_0 2
#define PIN_g 3
#define PIN_c 4
#define PIN_h 5
#define PIN_d 6
#define PIN_e 7
#define PIN_b 8
#define PIN_1 9
#define PIN_2 10
#define PIN_f 11
#define PIN_a 12
#define PIN_3 13
// 共有4個七段顯示器,分別由針腳PIN_0、PIN_1、PIN_2、PIN_3控制
// 七段顯示器裡有8個LED(包含小數點)
#define POS_NUM 4
#define SEG_NUM 8
const byte pos_pins[POS_NUM] = {PIN_0, PIN_1, PIN_2, PIN_3};
const byte seg_pins[SEG_NUM] = {PIN_a, PIN_b, PIN_c, PIN_d, PIN_e, PIN_f, PIN_g, PIN_h};
// 底下定義由七段顯示器顯示數字時所需要的資料
#define t true
#define f false
const boolean data[10][SEG_NUM] = {
{t, t, t, t, t, t, f, f}, // 0
{f, t, t, f, f, f, f, f}, // 1
{t, t, f, t, t, f, t, f}, // 2
{t, t, t, t, f, f, t, f}, // 3
{f, t, t, f, f, t, t, f}, // 4
{t, f, t, t, f, t, t, f}, // 5
{t, f, t, t, t, t, t, f}, // 6
{t, t, t, f, f, f, f, f}, // 7
{t, t, t, t, t, t, t, f}, // 8
{t, t, t, t, f, t, t, f}, // 9
};
// 一支方便的函式,以格式字串輸出到序列埠
void pf(const char *fmt, ... ){
char tmp[128]; // max is 128 chars
va_list args;
va_start (args, fmt );
vsnprintf(tmp, 128, fmt, args);
va_end (args);
}
// 設定某個七段顯示器所顯示的數字,
// 參數pos為0~3,指出想要更新哪一個七段顯示器,
// 參數n為0~9,顯示數字
void setDigit(int pos, int n){
if(pos < 0 || 3 < pos){
pf("error pos=%d\n", pos);
return;
}
// 控制想要更新哪一個七段顯示器,將其腳位設為LOW
// 其他腳位則設為HIGH,代表不更新。
for(int p = 0; p < POS_NUM; p++){
if(p == pos)
digitalWrite(pos_pins[p], LOW);
else
digitalWrite(pos_pins[p], HIGH);
}
// 寫入數字
if(0 <= n && n <= 9){
for(int i = 0; i < SEG_NUM; i++){
digitalWrite(seg_pins[i], data[n][i] == t ? HIGH : LOW);
}
}
else{
for(int i = 0; i < SEG_NUM; i++){
digitalWrite(seg_pins[i], LOW);
}
digitalWrite(PIN_h, HIGH);
pf("error pos=%d, n=%d\n", pos, n);
}
}
// 設定整個四合一型七段顯示器想要顯示的數字
// 參數number的範圍應是0~9999
void setNumber(int number)
{
int n0, n1, n2, n3;
n3 = number / 1000;
number %= 1000;
n2 = number / 100;
number %= 100;
n1 = number / 10;
n0 = number % 10;
// 求出每個位數的值後,分別更新
// 注意,此處以delay(5)隔開每個位數的更新
setDigit(0, n0); delay(5);
setDigit(1, n1); delay(5);
setDigit(2, n2); delay(5);
setDigit(3, n3); delay(5);
}
unsigned long time_previous;
void setup() {
Serial.begin(115200);
for(int i = 0; i < POS_NUM; i++){
pinMode(pos_pins[i], OUTPUT);
digitalWrite(pos_pins[i], HIGH);
}
for(int i = 0; i < SEG_NUM; i++){
pinMode(seg_pins[i], OUTPUT);
digitalWrite(seg_pins[i], LOW);
}
time_previous = millis();
pinMode(24, OUTPUT);
pinMode(26, OUTPUT);
Serial.begin(115200);
Serial.println("Temperature Sensor");
// 初始化
sensors.begin();
}
int number = 0;
void loop(void) {
// 要求匯流排上的所有感測器進行溫度轉換(不過我只有一個)
sensors.requestTemperatures();
// 取得溫度讀數(攝氏)並輸出,
// 參數0代表匯流排上第0個1-Wire裝置
Serial.println((int)((sensors.getTempCByIndex(0))*100));
delay(100);
digitalWrite(24, HIGH);
if((sensors.getTempCByIndex(0)) > 40)
{
digitalWrite(26, HIGH);
}
else
{
digitalWrite(26, LOW);
}
number = ((int)((sensors.getTempCByIndex(0))*100));
// 不斷地寫入數字
setNumber(number);
}
下面那24跟26腳是給繼電器的
Delete上面那個程式到底是哪裡讓我的七段一直閃?? 搞不懂 千位數就不會這樣
Delete你的loop()裡有delay(100);,所以七段顯示器會閃。
ReplyDelete四合一的七段顯示器,採用視覺暫留原理,必須不停地掃描顯示,不能停頓。
刪掉了 還是一樣耶
Delete是嗎?
ReplyDelete試試看吧
http://pastebin.com/U6QEwgj8
或可試試調整setNumber裡面的
ReplyDeletesetDigit(0, n0); delay(5);
setDigit(1, n1); delay(5);
setDigit(2, n2); delay(5);
setDigit(3, n3); delay(5);
嘗試看看把5調小或調大。
是不會閃了 不過7段顯示變成 (溫度亂打的)
ReplyDelete1953
1
1985
1
2123
2
多跳了一個千位出來 其他不會亮
delay(5)剛剛好
我剛剛看了一下 ARDUINO上那顆L一直亮滅(間隔1秒) 我記得他不是連著13腳 而且滅時就是只顯示千位的時候 跟這有關係嗎?
ReplyDelete只顯示1?其他不會亮,嗯,很奇怪。可能是晶片回傳錯的值。
ReplyDelete嗯,看來程式庫DallasTemperature預設為同步模式,會等溫度感測晶片轉換完後才回傳,
改成非同步模式,但要拉長等待時間。
試試吧http://pastebin.com/jkcJaNhq
只編譯過,沒實際跑過。
請問遺下這個程式碼還能上傳嗎 我也是遇到一樣問題
Delete上傳跟這份程式碼,有什麼關係?
Delete什麼問題?
因為你上面程式碼的連結已經失效 我想知道要怎麼更改這個問題
Delete我將sensors.setWaitForConversion(false);寫進SETUP後 有比較好一點 只是數字是一直閃爍的 但是可以判斷的出數字
想請問"拉長等待時間"是還要甚麼程式碼呢?
連結失效,嗯,我也找不到了。
Delete> 數字一直閃爍
可能程式裡有delay吧,影響7段顯示器的掃描程序。
your code?
#include
Delete#include
// Arduino數位腳位22接到1-Wire裝置
#define ONE_WIRE_BUS A3
// 運用程式庫建立物件
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
// 定義腳位
#define PIN_0 2
#define PIN_g 3
#define PIN_c 4
#define PIN_h 5
#define PIN_d 6
#define PIN_e 7
#define PIN_b 8
#define PIN_1 9
#define PIN_2 10
#define PIN_f 11
#define PIN_a 12
#define PIN_3 13
// 共有4個七段顯示器,分別由針腳PIN_0、PIN_1、PIN_2、PIN_3控制
// 七段顯示器裡有8個LED(包含小數點)
#define POS_NUM 4
#define SEG_NUM 8
const byte pos_pins[POS_NUM] = {PIN_0, PIN_1, PIN_2, PIN_3};
const byte seg_pins[SEG_NUM] = {PIN_a, PIN_b, PIN_c, PIN_d, PIN_e, PIN_f, PIN_g, PIN_h};
// 底下定義由七段顯示器顯示數字時所需要的資料
#define t true
#define f false
const boolean data[10][SEG_NUM] = {
{t, t, t, t, t, t, f, f}, // 0
{f, t, t, f, f, f, f, f}, // 1
{t, t, f, t, t, f, t, f}, // 2
{t, t, t, t, f, f, t, f}, // 3
{f, t, t, f, f, t, t, f}, // 4
{t, f, t, t, f, t, t, f}, // 5
{t, f, t, t, t, t, t, f}, // 6
{t, t, t, f, f, f, f, f}, // 7
{t, t, t, t, t, t, t, f}, // 8
{t, t, t, t, f, t, t, f}, // 9
};
// 一支方便的函式,以格式字串輸出到序列埠
void pf(const char *fmt, ... ){
char tmp[128]; // max is 128 chars
va_list args;
va_start (args, fmt );
vsnprintf(tmp, 128, fmt, args);
va_end (args);
}
// 設定某個七段顯示器所顯示的數字,
// 參數pos為0~3,指出想要更新哪一個七段顯示器,
// 參數n為0~9,顯示數字
void setDigit(int pos, int n){
if(pos < 0 || 3 < pos){
pf("error pos=%d\n", pos);
return;
}
// 控制想要更新哪一個七段顯示器,將其腳位設為LOW
// 其他腳位則設為HIGH,代表不更新。
for(int p = 0; p < POS_NUM; p++){
if(p == pos)
digitalWrite(pos_pins[p], LOW);
else
digitalWrite(pos_pins[p], HIGH);
}
// 寫入數字
if(0 <= n && n <= 9){
for(int i = 0; i < SEG_NUM; i++){
digitalWrite(seg_pins[i], data[n][i] == t ? HIGH : LOW);
}
}
else{
for(int i = 0; i < SEG_NUM; i++){
digitalWrite(seg_pins[i], LOW);
}
digitalWrite(PIN_h, HIGH);
pf("error pos=%d, n=%d\n", pos, n);
}
}
// 設定整個四合一型七段顯示器想要顯示的數字
// 參數number的範圍應是0~9999
void setNumber(int number)
{
int n0, n1, n2, n3;
n3 = number / 1000;
number %= 1000;
n2 = number / 100;
number %= 100;
n1 = number / 10;
n0 = number % 10;
// 求出每個位數的值後,分別更新
// 注意,此處以delay(5)隔開每個位數的更新
setDigit(0, n0); delay(5);
setDigit(1, n1); delay(5);
setDigit(2, n2); delay(5);
setDigit(3, n3); delay(5);
}
unsigned long time_previous;
void setup() {
Serial.begin(115200);
for(int i = 0; i < POS_NUM; i++){
pinMode(pos_pins[i], OUTPUT);
digitalWrite(pos_pins[i], HIGH);
}
for(int i = 0; i < SEG_NUM; i++){
pinMode(seg_pins[i], OUTPUT);
digitalWrite(seg_pins[i], LOW);
}
time_previous = millis();
pinMode(24, OUTPUT);
pinMode(26, OUTPUT);
Serial.begin(115200);
Serial.println("Temperature Sensor");
// 初始化
sensors.begin();
sensors.setWaitForConversion(false);
}
int number = 0;
void loop(void) {
// 要求匯流排上的所有感測器進行溫度轉換(不過我只有一個)
sensors.requestTemperatures();
// 取得溫度讀數(攝氏)並輸出,
// 參數0代表匯流排上第0個1-Wire裝置
Serial.println((int)((sensors.getTempCByIndex(0))*100));
digitalWrite(24, HIGH);
if((sensors.getTempCByIndex(0)) > 40)
{
digitalWrite(26, HIGH);
}
else
{
digitalWrite(26, LOW);
}
number = ((int)((sensors.getTempCByIndex(0))*100));
// 不斷地寫入數字
setNumber(number);
}
你在loop()裡呼叫sensors.getTempCByIndex的次數太多了吧。
Delete試試吧,只通過編譯。
https://pastebin.com/b4BVPque
你好 上面程式編譯不過ㄟ
Delete'class DallasTemperature' has no member named 'isConversionAvailable'
出現這段
你的DallasTemperature版本跟我的不一樣。
Delete改成
sensors.isConversionComplete();
試試
雖然我剛剛將 if(sensors.isConversionAvailable(addr)){]刪除就可以了
Delete現在加回來也可以使用
非常感謝老師!!找到我心頭大患!
刪除的話,程式行為是錯的。
Delete會讀到IDLE_TIME秒前的舊資料。嘛,也是可以啦。
不過那樣的話,就不必寫得這麼複雜了。
還是一樣耶 只不過兩個數字delay時間變長 單純只打七段0000-9999都不會這樣 沒關西喇 我在找找看 你休息吧 時間晚了不好意思浪費你這麼多時間 感謝你 至少比一開始有進步了
ReplyDelete嗯,我弄錯API了。
Delete把
sensors.setCheckForConversion(false);
改成
sensors.setWaitForConversion(false);
This comment has been removed by the author.
Delete太感謝你拉~~終於OK了 我原本還想說拿著一直閃的去給教授評分
ReplyDelete已經試過0000~9999,我也想製作能讓溫度顯示在四合一七段上面,請問能否提供電路圖 感恩
ReplyDelete沒有。
Delete請參考本篇跟Arduino練習:溫度感測DS18B20
http://yehnan.blogspot.tw/2013/01/arduinods18b20.html
然後撰寫程式碼。
另可參考拙作《Arduino輕鬆入門:範例分析與實作設計》
http://yehnan.blogspot.tw/2014/02/arduino_21.html
裡頭有介紹數位溫度感測器DS18B20、溫濕度感測器DHT11、溫度氣壓感測器BMP085,
不過都是使用LCD來顯示。
LCD的操作可參考這篇
以LiquidCrystal程式庫控制LCD(相容於Hitachi HD44780)
http://yehnan.blogspot.tw/2012/02/arduinoliquidcrystallcdhitachi-hd44780.html
請問5v蜂鳴器買不到可以使用3v串連100歐姆或是使用6 v的嗎
ReplyDelete假定使用5V的Arduino板子,
Delete用6V蜂鳴器的話,應不會燒壞,但推得動嗎?
用3V蜂鳴器的話,假設它需要10ma,那麼(5 - 3) / 0.01 = 200,應該串聯200 ohm電阻。
假設它需要15ma的話,那麼應該串聯約150 ohm電阻。
請問10k可變電阻是使用一般的還是精密的
ReplyDelete您是問哪一篇啊?
Delete一般的即可。
我是參考範例實作與實作分析7-1節
Delete請問蜂鳴器是將黑色接線接到200歐姆電阻,再將電阻接地嗎?
電阻接黑線或紅線,應該都可以。
Delete好 謝謝!
Delete請問 我使用200歐姆的電阻串連 蜂鳴器沒有發出聲音, LCD一子是顯示85度不會改變 是捨麼原因呢?
Delete85度是DS18B20的重置值,代表DS18B20沒有收到指令進行溫度轉換。
Delete原因很多,線路錯了、程式碼不對、DS18B20壞了、等等。
Delete好 我在檢查確認 謝謝
Delete您好,我使用書上寄生模式時溫度一子顯示85度,使用一般模式時 是負30~35之間,
Delete電路圖及程式碼都確認過沒有問題。
呃,您都確認過沒有問題了,那怎麼辦?
Delete請提供詳盡清晰的電路照片與程式碼。
程式碼是參照書上的
Delete#include
#include
#include
#define SERIAL_BAUDRATE 19200
#define LCD_RS_PIN 2
#define LCD_E_PIN 3
#define LCD_D4_PIN 4
#define LCD_D5_PIN 5
#define LCD_D6_PIN 6
#define LCD_D7_PIN 7
#define BUZZER_PIN 11
#define DS18B20_PIN 12
#define TEMPERATURE_HIGH_LIMIT 38 // 攝氏Celsius
#define TEMPERATURE_LOW_LIMIT 10 // 攝氏Celsius
#define NOTE_C5 523 // Do
#define NOTE_CS5 554
#define NOTE_D5 587 // Re
#define NOTE_DS5 622
#define NOTE_E5 659 // Mi
#define NOTE_F5 698 // Fa
#define NOTE_FS5 740
#define NOTE_G5 784 // So
#define NOTE_GS5 831
#define NOTE_A5 880 // La
#define NOTE_AS5 932
#define NOTE_B5 988 // Si
LiquidCrystal lcd(LCD_RS_PIN, LCD_E_PIN, LCD_D4_PIN, LCD_D5_PIN, LCD_D6_PIN, LCD_D7_PIN);
OneWire oneWire(DS18B20_PIN);
DallasTemperature tSensors(&oneWire);
float c;
float f;
void pf(const char *fmt, ... ){
char tmp[256];
va_list args;
va_start(args, fmt);
vsnprintf(tmp, 256, fmt, args);
va_end(args);
Serial.print(tmp);
}
void alarmHandler(uint8_t *){
lcd.setCursor(0, 1);
lcd.write(byte(1));
lcd.print(' ');
if(TEMPERATURE_HIGH_LIMIT <= c){
lcd.print("Too Hot!");
tone(BUZZER_PIN, NOTE_C5, 3000 / 4);
}
else if(c <= TEMPERATURE_LOW_LIMIT){
lcd.print("Too Cold!");
tone(BUZZER_PIN, NOTE_B5, 3000 / 4);
}
}
byte smileFace[8] = { // 笑臉
B00000,
B10001,
B00000,
B00000,
B10001,
B01110,
B00000,
};
byte cryFace[8] = { // 哭臉
B00000,
B10001,
B00000,
B00000,
B00000,
B01110,
B10001,
};
byte degreeCircle[8] = { // 代表「度」的小圈圈
B00010,
B00101,
B00010,
B00000,
B00000,
B00000,
B00000,
};
void setup(void)
{
Serial.begin(SERIAL_BAUDRATE);
while(!Serial){
}
lcd.createChar(0, smileFace);
lcd.createChar(1, cryFace);
lcd.createChar(2, degreeCircle);
lcd.begin(16, 2);
tSensors.begin();
int deviceCount = tSensors.getDeviceCount();
pf("There are %d device(s).\n", deviceCount);
for(int i = 0; i < deviceCount; i++){
uint8_t a[8];
tSensors.getAddress(a, i);
pf("Device index %d, address 0x %02x %02x %02x %02x %02x %02x %02x %02x\n",
i, a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7]);
// 設定溫度上下限
tSensors.setHighAlarmTemp(a, TEMPERATURE_HIGH_LIMIT);
tSensors.setLowAlarmTemp(a, TEMPERATURE_LOW_LIMIT);
tSensors.setAlarmHandler(alarmHandler); // 設定警告處理函式
}
}
void loop(void)
{
tSensors.requestTemperatures();
c = tSensors.getTempCByIndex(0);
f = tSensors.toFahrenheit(c);
Serial.print("Temperature is ");
Serial.print(c);
Serial.print(" degree(Celsius), ");
Serial.print(f);
Serial.println(" degree(Fahrenheit).");
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(c);
lcd.write(byte(2));
lcd.print('C');
lcd.setCursor(0, 1);
lcd.write(byte(0));
tSensors.processAlarms();
delay(1000);
}
請提供詳盡清晰的電路照片。
DeleteThis comment has been removed by the author.
ReplyDelete想請問此種7段顯示器可否透過74hc595來達到簡化街角的問題?
ReplyDelete以及想問老師74hc595是否可以串聯控制,謝謝
> 74hc595是否可以串聯控制
Delete可以,請參考
Arduino練習:霹靂車燈,以16個LED,製作霹靂車燈來回跑的效果,以兩顆74HC595控制16個LED。
http://yehnan.blogspot.tw/2012/02/arduino_19.html
> 此種7段顯示器可否透過74hc595來達到簡化街角的問題
可以。但似乎不太直覺。
通常會採用MAX7219,可控制8x8共陰極單色LED矩陣,或是8個七段顯示器(含小數點)。請參考拙作《Arduino輕鬆入門:範例分析與實作設計》,
http://yehnan.blogspot.tw/2014/02/arduino_21.html
的「5.5節 8x8 LED矩陣與MAX7219」。
好的,謝謝
DeleteThis comment has been removed by the author.
ReplyDelete請問如何將DHT11測出的數值加進單顆七段顯示器裡
ReplyDelete這是我用DHT11的程式
ReplyDelete#include
#define dht_dpin 2 //定義訊號要從Pin A0 進來
dht DHT;
void setup(){
Serial.begin(9600);
delay(300); //Let system settle
Serial.println("Humidity and temperature\n\n");
delay(700); //Wait rest of 1000ms recommended delay before
//accessing sensor
}
void loop(){
DHT.read11(dht_dpin); //去library裡面找DHT.read11
Serial.print("Humidity = ");
Serial.print(DHT.humidity);
Serial.print("% ");
Serial.print("temperature = ");
Serial.print(DHT.temperature);
Serial.println("C ");
delay(1000); //每1000ms更新一次
}
這一篇不就是在講七段顯示器嗎?有什麼問題嗎?
Delete另外,你程式碼loop()裡有delay(1000); ,這會對四合一的七段顯示器造成影響。
應改用http://yehnan.blogspot.tw/2014/03/arduinoled.html裡的程式寫法。
By the way,拙作「Arduino輕鬆入門:範例分析與實作設計」的第7.2節,讀取DHT11、顯示在LCD上,可供參考。
若是我用單顆的七段顯示器4顆(不是四合一)
Delete那是要個別寫入單顆嗎?
呃,沒試過。
Delete那樣的話,要二三十條線耶,
不過就不必處理四合一的七段顯示器的掃描問題。
我想先用4511做線會比較少
ReplyDelete嘛,少一半吧。
Delete想請問Arduino的A0~A3接至7447的A~D,之後將7447的A~G接至四位數的七段顯示器A~G,然後將四位數的七段顯示器0~3接至Arduino的9~12,要使四位數的七段顯示器顯示0~9的話,程式上要怎麼撰寫呢??
ReplyDelete7447應用於共陽極七段顯示器。
Delete四位數的七段顯示器、腳位0~3,控制顯示哪一個位數,例如腳位0為LOW、其他為HIGH,代表控制第0個位數。(也可能相反。)
四位數的七段顯示器A~G,由7447的A0~A3控制,
請參考拙作《Arduino輕鬆入門:範例分析與實作設計》的5.2節,該節使用4511(控制共陰極七段顯示器),原理相同。
謝謝!!我寫出來了^^
Delete可以請問一下那個Arduino和7位數碼管的模擬圖是用什麼軟件畫出來的嗎?
ReplyDeleteFritzing
Delete多谢啦
Delete請教一下葉老師,若我用74164也可以嗎? 若不行CODE 應該要如何修改?
ReplyDelete已於另一篇回覆。
Delete葉老師,我現在會1個seg顯示個位數,如果要進位成十位數,要如何進位
Delete不知道如何回答。
Delete這一篇不就是介紹如何使用四合一的七段顯示器嗎?
不好意思請教一下,假如要將按鍵記數顯示於七段顯示器上,該將程式如何給合併,目前只知道顯示七段顯示器0000~9999
ReplyDelete功能的程式,
按鍵記數:http://ohcoder.com/blog/2015/12/06/arduino-fun-button-count/
七段顯示器0000~9999:http://www.arduino.cn/thread-3140-1-1.html
> 該將程式如何給合併
Delete這不是問題,而是需求。
請問問題是什麼?
不好意思請問一下,本人我剛學,所以不懂為什麼void loop裡的意思
ReplyDelete// 經過一秒後就讓number加1
unsigned long time_now = millis();
if(time_now - time_previous > 1000){
number++;
time_previous += 1000;
}
如果我直接用
delay(1000)
number++
也可以嗎?
為什麼不實際試試看呢?
Delete答案是不行,
因為必須使用掃描的方式不斷地顯示每一個七段顯示器,只要掃描速度夠快,基於視覺暫留原理,人眼便無法察覺,以為所有數字皆為同時顯示。
使用delay的話,就沒辦法達成上述要求。
謝謝老師,我還有一個問題。
Delete我想做三組2位數的 輝光管 掃描
因為有3個數字所以我做了3個setNumber()的副程式
所以丟給它掃描是
set_s(s);
set_m(m);
set_h(h); //功能是setNumber()的功能
它會不會變成一次3個setDigit()同時輸出?
看不太懂你的問題。
Delete> 會不會變成一次3個setDigit()同時輸出?
不會。
就會不會同時執行那三個副程式
Delete不會。Arduino沒有多個CPU核心,無法平行處理。
Delete執行程式都是從上到下,依序執行。
原來如此,謝謝老師~
DeleteThis comment has been removed by the author.
ReplyDelete老師您好,我想請問一下,我做的實驗是跟這個4合一七段的程式合併
ReplyDelete顯示感測器(MCP9701A)的數值在七段上,我們做到最後已經可以顯示溫度了,但是每個位數都會一直閃,
我們有嘗試參考了老師您在17/12/14解決的方法,只不過網址打開不了
我們程式如下:
int sensorPin = A1;
int analogin = 0;
int ledg = 10; //選擇引腳的LED
int ledp = 11;//選擇引腳的LED
int tmp;
int i,j;
int count=0;
int number;
unsigned long time=0;
const byte num[10]=
{ B11000000,B11111001,B10100100,B10110000,B10011001,
B10010010,B10000010,B11111000,B10000000,B10010000};
const int seg[]={2,3,4,5,6,7,8,9};
const int digit[]={10,11,12,13};
void setup() {
Serial.begin(9600);
pinMode(ledg,OUTPUT); // 定義LED為輸出腳
pinMode(ledp,OUTPUT); // 定義LED為輸出腳
analogReference(INTERNAL); //内部1.1V
for(i=0;i<8;i++)
pinMode(seg[i],OUTPUT);
for(i=0;i<4;i++)
{
pinMode(digit[i],OUTPUT);
digitalWrite(digit[i],HIGH);
}
}
void loop() {
// read the value from the sensor:
int tmp;
analogin = analogRead(sensorPin);
Serial.println(analogin);
tmp=(analogin-400)/19.5;
Serial.print("tmp=");
Serial.println(tmp);
if(tmp>=26) \\設定當溫度大於等於26,ledp亮;相反,ledg亮。
{
digitalWrite(ledp,HIGH);
digitalWrite(ledg,LOW);
delay(500);
}
else
{
digitalWrite(ledg,HIGH);
digitalWrite(ledp,LOW);
delay(500);
}
number=count;
for(i=3;i>=0;i--)
{
for(j=0;j<8;j++)
{
if(bitRead(num[number%10],j))
digitalWrite(seg[j],HIGH);
else
digitalWrite(seg[j],LOW);
}
digitalWrite(digit[i],LOW);
delay(5);
digitalWrite(digit[i],HIGH);
number=number/10;
count=tmp;
}
}
老師您好,我想請問一下,我做的實驗是跟這個4合一七段的程式合併
ReplyDelete顯示感測器(MCP9701A)的數值在七段上,我們做到最後已經可以顯示溫度了,但是每個位數都會一直閃,
我們有嘗試參考了老師您在17/12/14解決的方法,只不過網址打開不了
我們程式如下:
int sensorPin = A1;
int analogin = 0;
int ledg = 10; //選擇引腳的LED
int ledp = 11;//選擇引腳的LED
int tmp;
int i,j;
int count=0;
int number;
unsigned long time=0;
const byte num[10]=
{ B11000000,B11111001,B10100100,B10110000,B10011001,
B10010010,B10000010,B11111000,B10000000,B10010000};
const int seg[]={2,3,4,5,6,7,8,9};
const int digit[]={10,11,12,13};
void setup() {
Serial.begin(9600);
pinMode(ledg,OUTPUT); // 定義LED為輸出腳
pinMode(ledp,OUTPUT); // 定義LED為輸出腳
analogReference(INTERNAL); //内部1.1V
for(i=0;i<8;i++)
pinMode(seg[i],OUTPUT);
for(i=0;i<4;i++)
{
pinMode(digit[i],OUTPUT);
digitalWrite(digit[i],HIGH);
}
}
void loop() {
// read the value from the sensor:
int tmp;
analogin = analogRead(sensorPin);
Serial.println(analogin);
tmp=(analogin-400)/19.5;
Serial.print("tmp=");
Serial.println(tmp);
if(tmp>=26) \\設定當溫度大於等於26,ledp亮;相反,ledg亮。
{
digitalWrite(ledp,HIGH);
digitalWrite(ledg,LOW);
delay(500);
}
else
{
digitalWrite(ledg,HIGH);
digitalWrite(ledp,LOW);
delay(500);
}
number=count;
for(i=3;i>=0;i--)
{
for(j=0;j<8;j++)
{
if(bitRead(num[number%10],j))
digitalWrite(seg[j],HIGH);
else
digitalWrite(seg[j],LOW);
}
digitalWrite(digit[i],LOW);
delay(5);
digitalWrite(digit[i],HIGH);
number=number/10;
count=tmp;
}
}
腳位10為什麼用於ledg、也用於digit?
Delete使用掃描方式,必須不斷地顯示每一個七段顯示器,只要掃描速度夠快,基於視覺暫留原理,人眼便無法察覺,以為所有數字皆為同時顯示。
你loop裡有delay(500);,暫停太久了,導致掃描速度不快,所以會閃。
把兩個delay(500);都刪除,應該就可以了吧。
This comment has been removed by the author.
Delete謝謝您,已經成功了~
ReplyDelete腳位10 11原先是四合一七段顯示器的千位及百位,後來發現千位與百位不會用到,便把10 11當作led的腳位來使用了,一下子忘記改過來了~
另外我想請問一下,如果要讓溫度感測器能每10秒偵測一次的話,我應該要加delay()嗎? 還是要用其他的方式呢?
請參考
Deletehttp://yehnan.blogspot.tw/2014/03/arduinoled.html
int digit1=12;
ReplyDeleteint digit2=11;
int digit3=10;
int digit4=9;
int segA=2;
int segB=3;
int segC=4;
int segD=5;
int segE=6;
int segF=7;
int segG=8;
byte seven_seg_digits[10][7]=
{
{1,1,1,1,1,1,0},//0
{0,1,1,0,0,0,0},//1
{1,1,0,1,1,0,1},//2
{1,1,1,1,0,0,1},//3
{0,1,1,0,0,1,1},//4
{1,0,1,1,0,1,1},//5
{0,0,1,1,1,1,1},//6
{1,1,1,0,0,1,0},//7
{1,1,1,1,1,1,1},//8
{1,1,1,0,1,1,0},//9
};
void setup(){
pinMode(segA,OUTPUT);
pinMode(segB,OUTPUT);
pinMode(segC,OUTPUT);
pinMode(segD,OUTPUT);
pinMode(segE,OUTPUT);
pinMode(segF,OUTPUT);
pinMode(segG,OUTPUT);
pinMode(digit1,OUTPUT);
pinMode(digit2,OUTPUT);
pinMode(digit3,OUTPUT);
pinMode(digit4,OUTPUT);
}
void loop(){
displayNumber(millis()/1000);
}
void displayNumber(int toDisplay){
#define DIGIT_ON HIGH
#define DIGIT_OFF LOW
for(int digit=1;digit<5;digit++){
switch(digit){
case 1:
digitalWrite(digit4,HIGH);
lightNumber(toDisplay % 10);
toDisplay /=10;
break;
case 2:
digitalWrite(digit3,HIGH);
lightNumber(toDisplay % 6);
toDisplay /=6;
break;
case 3:
digitalWrite(digit2,HIGH);
lightNumber(toDisplay % 10);
toDisplay /=10;
break;
case 4:
digitalWrite(digit1,HIGH);
lightNumber(toDisplay % 6);
toDisplay /=6;
break;
}
delayMicroseconds(6000);
lightNumber(10);
digitalWrite(digit4,LOW);
digitalWrite(digit3,LOW);
digitalWrite(digit2,LOW);
digitalWrite(digit1,LOW);
}
}
void lightNumber(byte numberToDisplay){
byte pin=2;
for(byte seg=0; seg<7; ++seg){
digitalWrite(pin, seven_seg_digits[numberToDisplay][seg]);
++pin;
}
}
都只會顯示8888跟0000請問是什摸
問題啊
lightNumber(10); 這一行是什麼作用?
Delete我是照課本打的lightNumber(10);關閉七段顯示器所有LED
Delete是嗎? 根據你的程式碼,
Deleteseven_seg_digits的有效索引值是0~9,但你卻傳入10。
四合一的七段顯示器,啟用電壓沒搞錯嗎?HIGH是啟用嗎?還是LOW?
DeleteHIGH是啟用
Delete只覺得lightNumber(10);這行怪怪的,
Delete看不出有什麼問題。
This comment has been removed by the author.
ReplyDelete請問若一個Arduino 的板子接兩個四合一ok嗎?目前遇到一個狀況,當我接兩個的時候千位數的燈會比較亮,其餘的都很暗
ReplyDelete但若只接一個四合一則沒有這個問題
那就另外提供電源給四合一的七段顯示器。
Delete我是使用mega的版子,22~33為1號四合一,34~45為2號四合一,您上述教學的線路規畫我不知道該如何另外提供電源耶,是否可以指導小弟呢?謝謝老師
Delete自己弄的話,可以加電晶體,類似這樣子
Deletehttps://electronics.stackexchange.com/questions/93155/cheap-4-digit-7-segment-display-driver
也可用TM1637,專門用來驅動7-seg display的晶片,
http://playground.arduino.cc/Main/TM1637
請問老師,加電晶體,這個電晶體是要用什麼型號的呢?
Delete2N2222
DeleteThis comment has been removed by the author.
ReplyDelete老師妳好 ,我有跟前面幾位有一樣的問題,數字顯示出來只有千位數字恆亮,其他位數都會一閃一閃的,請問這樣該如何解決?
ReplyDelete程式碼:
// 匯入程式庫標頭檔
#include
#include
// Arduino數位腳位10接到1-Wire裝置
#define ONE_WIRE_BUS 10
// 運用程式庫建立物件
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
// 定義腳位
#define PIN_0 A5
#define PIN_g A4
#define PIN_c A3
#define PIN_h A2
#define PIN_d A1
#define PIN_e A0
#define PIN_b 2
#define PIN_1 3
#define PIN_2 4
#define PIN_f 5
#define PIN_a 6
#define PIN_3 7
// 共有4個七段顯示器,分別由針腳PIN_0、PIN_1、PIN_2、PIN_3控制
// 七段顯示器裡有8個LED(包含小數點)
#define POS_NUM 4
#define SEG_NUM 8
const byte pos_pins[POS_NUM] = {PIN_0, PIN_1, PIN_2, PIN_3};
const byte seg_pins[SEG_NUM] = {PIN_a, PIN_b, PIN_c, PIN_d, PIN_e, PIN_f, PIN_g, PIN_h};
// 底下定義由七段顯示器顯示數字時所需要的資料
#define t true
#define f false
const boolean data[10][SEG_NUM] = {
{t, t, t, t, t, t, f, f}, // 0
{f, t, t, f, f, f, f, f}, // 1
{t, t, f, t, t, f, t, f}, // 2
{t, t, t, t, f, f, t, f}, // 3
{f, t, t, f, f, t, t, f}, // 4
{t, f, t, t, f, t, t, f}, // 5
{t, f, t, t, t, t, t, f}, // 6
{t, t, t, f, f, f, f, f}, // 7
{t, t, t, t, t, t, t, f}, // 8
{t, t, t, t, f, t, t, f}, // 9
};
// 一支方便的函式,以格式字串輸出到序列埠
void pf(const char *fmt, ... ){
char tmp[128]; // max is 128 chars
va_list args;
va_start (args, fmt );
vsnprintf(tmp, 128, fmt, args);
va_end (args);
Serial.print(tmp);
}
// 設定某個七段顯示器所顯示的數字,
// 參數pos為0~3,指出想要更新哪一個七段顯示器,
// 參數n為0~9,顯示數字
void setDigit(int pos, int n){
if(pos < 0 || 3 < pos){
pf("error pos=%d\n", pos);
return;
}
// 控制想要更新哪一個七段顯示器,將其腳位設為LOW
// 其他腳位則設為HIGH,代表不更新。
for(int p = 0; p < POS_NUM; p++){
if(p == pos)
digitalWrite(pos_pins[p], LOW);
else
digitalWrite(pos_pins[p], HIGH);
}
// 寫入數字
if(0 <= n && n <= 9){
for(int i = 0; i < SEG_NUM; i++){
digitalWrite(seg_pins[i], data[n][i] == t ? HIGH : LOW);
}
}
else{
for(int i = 0; i < SEG_NUM; i++){
digitalWrite(seg_pins[i], LOW);
}
digitalWrite(PIN_h, HIGH);
pf("error pos=%d, n=%d\n", pos, n);
}
}
// 設定整個四合一型七段顯示器想要顯示的數字
// 參數number的範圍應是0~9999
void setNumber(int number)
{
int n0, n1, n2, n3;
n3 = number / 1000;
number %= 1000;
n2 = number / 100;
number %= 100;
n1 = number / 10;
n0 = number % 10;
// 求出每個位數的值後,分別更新
// 注意,此處以delay(5)隔開每個位數的更新
setDigit(0, n0); delay(5);
setDigit(1, n1); delay(5);
setDigit(2, n2); delay(5);
setDigit(3, n3); delay(5);
}
unsigned long time_previous;
void setup() {
Serial.begin(9600);
for(int i = 0; i < POS_NUM; i++){
pinMode(pos_pins[i], OUTPUT);
digitalWrite(pos_pins[i], HIGH);
}
for(int i = 0; i < SEG_NUM; i++){
pinMode(seg_pins[i], OUTPUT);
digitalWrite(seg_pins[i], LOW);
}
Serial.begin(9600);
Serial.println("Temperature Sensor");
// 初始化
sensors.begin();
}
int number = 0;
void loop() {
// 要求匯流排上的所有感測器進行溫度轉換(不過我只有一個)
sensors.requestTemperatures();
// 取得溫度讀數(攝氏)並輸出,
// 參數0代表匯流排上第0個1-Wire裝置
Serial.println((int)((sensors.getTempCByIndex(0))*100));
delay(100);
number = ((int)((sensors.getTempCByIndex(0))*100));
delay(100);
// 不斷地寫入數字
setNumber(number);
}
因為delay,想辦法去掉loop裡的delay。
Delete我把兩個delay(100);都去掉了但顯示器還是一直閃(似乎四位都會閃,不過千位數字很亮,百十個位就相對暗很多),有再接六伏電源了,不過還是一樣。
Delete把loop改成
Deletevoid loop() {
// 要求匯流排上的所有感測器進行溫度轉換(不過我只有一個)
sensors.requestTemperatures();
// 取得溫度讀數(攝氏)並輸出,
// 參數0代表匯流排上第0個1-Wire裝置
float t = sensors.getTempCByIndex(0);
Serial.println((int)(t*100));
number = ((int)(t*100));
// 不斷地寫入數字
setNumber(number);
}
試試吧,因為getTempCByIndex會花時間。
如果還不行,就要多改一點了,不要常常去呼叫getTempCByIndex。
老師您好,我也是在結合DS18B20和七段顯示器上出現千位數字很亮 其他位數字有閃爍情形
Delete以下附上code 其他函式設定與 "ㄚ哭拿" 相同就僅附上相異之處
還請麻煩老師幫忙
void setup() {
Serial.begin(115200);
for(int i = 0; i < POS_NUM; i++){
pinMode(pos_pins[i], OUTPUT);
digitalWrite(pos_pins[i], HIGH);
}
for(int i = 0; i < SEG_NUM; i++){
pinMode(seg_pins[i], OUTPUT);
digitalWrite(seg_pins[i], LOW);
}
sensors.begin();
sensors.getAddress(tempDeviceAddress, 0);
sensors.setResolution(tempDeviceAddress, resolution);
\\參考DallasTemperature範本中 修改解晰度用以提升反應時間 範本建議 int resolution = 9;
sensors.setWaitForConversion(false);
}
void loop() {
sensors.requestTemperatures();
setNumber(sensors.getTempCByIndex(0)*100);
}
想請問老師 上面賴柏瑋和亞諠是怎麼解決閃爍的問題的呢?
感謝
> 賴柏瑋和亞諠是怎麼解決閃爍的問題的呢?
Delete修改程式。
你的程式要改的話,可參考DallasTemperature的範例,
https://github.com/milesburton/Arduino-Temperature-Control-Library/tree/master/examples
其中的WaitForConversion與WaitForConversion2,
在loop裡盡量少呼叫requestTemperatures與getTempCByIndex。
不好意思,我想問要怎麼把四位數七段顯示器結合LED燈做成類似紅綠燈的裝置
ReplyDelete指令如下
綠燈亮10秒、七段顯示器顯示倒數0010、0009、0008...;
黃燈亮1秒、七段顯示器顯示倒數0001、0000;
紅燈亮10秒、七段顯示器顯示倒數0010、0009、0008...;
你這樣問,我不知道怎麼回答。
Delete把電路組起來,寫寫程式吧。
應該會用到 有限狀態機 的程式撰寫技巧。
要如何改成電子鐘(分跟小時)
ReplyDelete請問如何把HC-SR04這個測距吐出來的資料~用4個7段顯示器顯示呢?
ReplyDelete請問如何把HC-SR04這個測距吐出來的資料~用4個7段顯示器顯示呢?
ReplyDelete請問如何把HC-SR04這個測距吐出來的資料~用4個7段顯示器顯示呢?
ReplyDelete請問一下我要如何把上面的程式加一個按鈕來控制
ReplyDelete