KaoChin 發表於 2015-11-28 12:12:19

DS3231(IIC)+OLED12864(IIC) 串接的問題

本帖最後由 KaoChin 於 2015-11-28 12:18 編輯

我想做一個簡單的實驗
只是把及時時鐘(RTC) DS3231 的數據,傳到 OLED12864 做成一個時鐘
藉此瞭解串接兩個 IIC 的程式技巧
板子為 MEGA 2560
OLED12664 使用的函數庫是 Adafruit_ssd1306syp

當然,遇到了一些問題,讀取RTC的動作,造成 OLED 無法繼續正常工作我想大致上的原因在於 記憶體位置的讀寫
所以我寫了一個程式用來 debug

程式規劃如下
int i;
loop 每一週期 i 就會增加 1
每個週期都會在 OLED 與 serial monitor 輸出 ith

並且在 i >5 時 開始讀取 RTC
並在 OLED 與 serial monitor 輸出 "ith"

程式如下
(只呈現 loop 的部分)

void loop()
{
i=i+1;

display.update();
Serial.print("i=");Serial.println(i);
//delay(1000);
display.clear();
display.setTextSize(2);
display.setTextColor(WHITE);
display.setCursor(0,0);
display.print(i, DEC);display.println("th");
if (i>255) i=0;
delay(100);
if (i>5){
   Wire.beginTransmission(DS3231_I2C_ADDRESS);
   Wire.write(0x01);
//AWire.requestFrom(DS3231_I2C_ADDRESS, 1);
//Bminute=Clock.getMinute();
//CWire.endTransmission();
   display.println();
   display.println("WIRE test");
   Serial.println("WIREtest");
}
}



其中
Wire.beginTransmission(DS3231_I2C_ADDRESS);
Wire.write(0x01);
//A Wire.requestFrom(DS3231_I2C_ADDRESS, 1);
//B minute=Clock.getMinute();
//C Wire.endTransmission();
是讀取 RTC 的程式

執行結果1.
如果 A B C 三行程式,其中的一行"沒有"被 comment
那麼,OLED 的輸出在 i>5 之後將會停止
而 serial monitor 會一直輸出 ,i 會大於 5 一直繼續加上去,而 "WIRE test"這行字也會一直出現在 serial monitor2.
如果 A B C 三行程式,其中的一"有"被 comment
那麼,OLED 與 serial monitor 會一起一樣的正常輸出


換句話說,讀取RTC的動作,造成 OLED 無法繼續正常工作

曾經試著在 if 的 loop
1.關掉 iic 再 打開 iic 可是沒用
2.做 display.initialize(); (OLED 的初始化,他會重置相關記憶體,程式在最後) 也沒用

所以我在想,是不是讀取記憶體的指標位置變了,使得 OLED 無法運作
請問有人有經驗,方法,或建議 解決這個問題嗎?
感謝您的回覆

以下為display.initialize() 程式碼 (當然有宣告display 為 Adafruit_ssd1306syp 類別 )


ool Adafruit_ssd1306syp::initialize()
{
      //setup the pin mode
      pinMode(m_sda,OUTPUT);
      pinMode(m_scl,OUTPUT);

      //malloc the framebuffer.
      //malloc(記憶體大小)
      //m_pFramebuffer = (unsigned char*)malloc(SSD1306_FBSIZE);
      //將 malloc(SSD1306_FBSIZE) 轉成 unsigned char "指標" 放在 m_pFramebuffer
      m_pFramebuffer = (unsigned char*)malloc(SSD1306_FBSIZE);
      if(m_pFramebuffer == 0){
                return false;
      }
      //void *memset(void *s, int c, size_t n);

   //memset 設定位元組中的位元值,
      //設定的方式從s 開始將n 個位元組設定成為c 的位元值並回傳s,
   //開始將n 個位元組設定成為c 的位元值並回傳s,經常運用的範圍是在將位元組的位元值清為0。
      memset(m_pFramebuffer,0,SSD1306_FBSIZE);//clear it.

      //write command to the screen registers.
      writeCommand(SSD1306_CMD_DISPLAY_OFF);//display off
      writeCommand(0x00);//Set Memory Addressing Mode
      writeCommand(0x10);//00,Horizontal Addressing Mode;01,Vertical Addressing Mode;10,Page Addressing Mode (RESET);11,Invalid
      writeCommand(0x40);//Set Page Start Address for Page Addressing Mode,0-7
      writeCommand(0xB0);//Set COM Output Scan Direction
      writeCommand(0x81);//---set low column address
      writeCommand(0xCF);//---set high column address
      writeCommand(0xA1);//--set start line address
      writeCommand(0xA6);//--set contrast control register
      writeCommand(0xA8);
      writeCommand(0x3F);//--set segment re-map 0 to 127
      writeCommand(0xC8);//--set normal display
      writeCommand(0xD3);//--set multiplex ratio(1 to 64)
      writeCommand(0x00);//
      writeCommand(0xD5);//0xa4,Output follows RAM content;0xa5,Output ignores RAM content
      writeCommand(0x80);//-set display offset
      writeCommand(0xD9);//-not offset
      writeCommand(0xF1);//--set display clock divide ratio/oscillator frequency
      writeCommand(0xDA);//--set divide ratio
      writeCommand(0x12);//--set pre-charge period
      writeCommand(0xDB);//
      writeCommand(0x40);//--set com pins hardware configuration
      writeCommand(0x8D);//--set vcomh
      writeCommand(0x14);//0x20,0.77xVcc
      writeCommand(0xAF);//--set DC-DC enable
      writeCommand(SSD1306_CMD_DISPLAY_ON);//--turn on oled panel

      delay(10);//wait for the screen loaded.
      return true;

超新手 發表於 2015-11-29 06:35:30

沒看到 Clock.getMinute(); 是怎麼寫的
不過, 先改成這看看
Wire.beginTransmission(DS3231_I2C_ADDRESS);
Wire.write(0x01);
Wire.endTransmission(); // 移到這邊
Wire.requestFrom(DS3231_I2C_ADDRESS, 1);
minute=Clock.getMinute();
也就是把 ABC 變成 CAB

KaoChin 發表於 2015-11-29 09:50:36

感謝樓上的建議

今天早上想了一下,還有一個可能的原因是
一開始先讓 OLED 跑, RTC 不跑
系統只有一個 IIC device 動作(RTC 可以視為不存在)。。。板子內建的上拉電位夠力
但是,RTC 加入後,系統變成兩個 device
由於 OLED 串接於 RTC 之後,OLED 上拉電位不夠
所以,OLED 就無法動作了

等下去買兩個 10K Ohm 電阻來試試!

KaoChin 發表於 2015-11-30 10:25:26

筆記一下,以上的方法都沒用 @@

超新手 發表於 2015-11-30 10:46:57

本帖最後由 超新手 於 2015-11-30 10:53 編輯

請問一下
如果改成 CAB 的執行結果會怎樣?也是不會一直執行嗎?

因為你沒把 Clock.getMinute(); 內容 PO 出來
它應該是類似
while(Wire.available()) {
Wire.read();
.....
}

KaoChin 發表於 2015-12-1 13:43:16

請問一下
如果改成 CAB 的執行結果會怎樣?也是不會一直執行嗎?

因為你沒把 Clock.getMinute(); 內容 PO ...
超新手 發表於 2015-11-30 10:46 http://www.robofun.net/forum/images/common/back.gif

不能執行事實上
ABC 只要存在任何一條,就無法執行
跟 Clock.getMinute() 內容沒有關係

超新手 發表於 2015-12-1 13:54:28

我是說, 我程式順序改成 CAB
你可以看一下 Wire 範例 SFRRanger_reader
其實程式應該要寫成
Wire.beginTransmission(DS3231_I2C_ADDRESS);
Wire.write(0x01);
Wire.endTransmission();
Wire.requestFrom(DS3231_I2C_ADDRESS, 1);
.........
Wire.available())   
reading = Wire.read();

KaoChin 發表於 2015-12-2 10:01:14

改過了,都沒用,就算只有以下三行(依順序,我一開始就是這樣寫的,後來才換順序看看),也是不能跑
Wire.beginTransmission(DS3231_I2C_ADDRESS);
Wire.write(0x01);
Wire.endTransmission();

超新手 發表於 2015-12-2 12:30:53

剛剛查了Adafruit_ssd1306syp的 library
如果你也是同一個libray的話
https://github.com/Miyeah/Arduin ... Adafruit_ssd1306syp
它是用 i/o 去模擬 i2c,
但是 Wire 是用 ic 本身硬體的 i2c
切來切去會不正常, 應該不算反常...
頁: [1]
查看完整版本: DS3231(IIC)+OLED12864(IIC) 串接的問題