Translate

顯示具有 Arduino 標籤的文章。 顯示所有文章
顯示具有 Arduino 標籤的文章。 顯示所有文章

2023年11月29日 星期三

arduino使用七段顯示器,腳位使用可以簡化程式碼並使用PORT暫存器直接一次將值送給七段

unsigned long time_delay=0;
byte state_7=0;
byte segCount=0;
//共陽極 dp a b c d e f g
byte seven_seg_digits[10] = {0b00000001,  // = 0
                             0b01001111,  // = 1
                             0b00010010,  // = 2
                             0b00000110,  // = 3
                             0b01001100,  // = 4
                             0b00100100,  // = 5
                             0b00100000,  // = 6
                             0b00001111,  // = 7
                             0b00000000,  // = 8
                             0b00000100   // = 9
                             };

void setup() {                
  pinMode(2, OUTPUT);   //a
  pinMode(3, OUTPUT);  //b
  pinMode(4, OUTPUT); //c
  pinMode(5, OUTPUT); //d
  pinMode(6, OUTPUT); //e
  pinMode(7, OUTPUT); //f
  pinMode(8, OUTPUT); //g
}
    
void sevenSegWrite(byte digit) {  //顯示特定數字的副程式
  byte pin = 2;  //我們的七段顯示是從pin2開始的
  for (byte i = 0; i < 7;i++) {
    digitalWrite(pin+i, (seven_seg_digits[digit]>>(6-i))&0b00000001);
  }
}

void loop() {
  //數字從9開始倒數,每個數字間隔1秒
  if (state_7==0)
  {
    sevenSegWrite(segCount);
    time_delay=millis();
    state_7=1;
  }
  else
  {
    if((millis()-time_delay)>1000)
    {
      state_7=0;
      
      if(segCount==9)
      {
        segCount=0;
      }
      else
      {
        segCount++;
      }
    }
  }

}

unsigned long time_delay=0;
byte state_7=0;
byte segCount=0;
//共陽極 dp a b c d e f g
byte seven_seg_digits[10] = {0b00000001,  // = 0
                             0b01001111,  // = 1
                             0b00010010,  // = 2
                             0b00000110,  // = 3
                             0b01001100,  // = 4
                             0b00100100,  // = 5
                             0b00100000,  // = 6
                             0b00001111,  // = 7
                             0b00000000,  // = 8
                             0b00000100   // = 9
                             };

void setup() {    
  DDRD=0x7f;//設定0~7腳為輸出
}
void loop() {
  //數字從9開始倒數,每個數字間隔1秒
  if (state_7==0)
  {
    PORTD=seven_seg_digits[segCount];
    time_delay=millis();
    state_7=1;
  }
  else
  {
    if((millis()-time_delay)>1000)
    {
      state_7=0;
      
      if(segCount==9)
      {
        segCount=0;
      }
      else
      {
        segCount++;
      }
    }
  }

}

利用tinkercad模擬arduino控制LCD自建字型

 參考網站:臺南市教育局科技教育網-自建字型





#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(32,16,2);
 
byte yearChar[8]={B01000,B11111,B00010,B01111,B01010,B11111,B00010,B00000};
byte moonChar[8]={B01111,B01001,B01111,B01001,B01111,B01001,B11101,B00000};
byte dayChar[8]={B01111,B01001,B01001,B01111,B01001,B01001,B01111,B00000};
int years=2023;
byte moons=11;
byte days=29;
void setup() 
{
  lcd.init();
  lcd.backlight(); 
  lcd.createChar(0,yearChar);
  lcd.createChar(1,moonChar);
  lcd.createChar(2,dayChar);  
}   
void loop() 
{
  lcd.setCursor(0,0);
  lcd.print(years);
  lcd.write(byte(0)); 
  lcd.print(moons);
  lcd.write(byte(1));
  lcd.print(days);
  lcd.write(byte(2));
}




2023年4月17日 星期一

使用tinkercad模擬arduino 控制LCD 16X2(I2C) PCF8574

 tinkercad 預設的LCD I2C範例係使用MCP23008型

電路接線

將LCD的VCC接到Arduino板上的5V、GND(LCD)接GND(Arduino)、SCL(LCD)接A5或Aref左邊第2腳(Arduino)、SDA(LCD)接A4或Aref左邊第1腳(Arduino)


但因為自已係使用PCF8574型,範例程式沒辦法使用。網路上找了一些資料如下面範例。

點選LCD可以將類型改成PCF8574型,地址用預設的32,也可以改成您想要的,但呼叫元件時第1個參數記得改您最後設定值。


#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(32,16,2);  //設定參數(地址,行數,列數)

void setup()
{
  lcd.init();                      // initialize the lcd 
  // Print a message to the LCD.
  lcd.backlight();
  lcd.setCursor(0,0);
  lcd.print("Hello, world!");
  lcd.setCursor(0,1);
  lcd.print("2023/04/17");
  lcd.setCursor(0,2);
}

void loop()
{

}

2018年12月3日 星期一

2018年10月3日 星期三

Excel VBA選擇COM Port讀取Arduino資料

請先學習Excel VBA 尋找可用的RS232 port利用Excel VBA利用串列埠RS232讀取Arduino資料

新增一個NETComm1、TextBox1、CommandButton1、CommandButton2、ComboBox1、Label1

備註:TextBox1屬性MultiLine請設為True



表單畫面如下:

程式碼:

Private Sub CommandButton1_Click()
    On Error Resume Next
    NETComm1.SThreshold = 1
    NETComm1.RThreshold = 1
    NETComm1.CommPort = ComboBox1.Text
    If NETComm1.PortOpen = False Then  'if the serial port is closed
        NETComm1.PortOpen = True       'open the serial port
        CommandButton1.Enabled = False
    End If
    If Err Then MsgBox Error$, 48
End Sub

Private Sub CommandButton2_Click()
    'Close serial port on exit
    On Error Resume Next    'Error handler
    
    If NETComm1.PortOpen = True Then    'check if the serial port is open
        NETComm1.PortOpen = False       'close the serial port
    End If
    If Err Then MsgBox Error$, 48     'Display error in message box
    End
End Sub


Private Sub NETComm1_OnComm()
    Static Buffer As String
    Dim CRLFPos As Integer
    Buffer = Buffer & NETComm1.InputData 'or whatever name you use for the instance of NETComm
    
    CRLFPos = InStr(Buffer, vbCr)
    If CRLFPos > 0 Then
        Dim MyData As String
        d = Now()
        MyData = d & Mid(Buffer, 1, CRLFPos - 1) & vbCrLf
        TextBox1.Text = TextBox1.Text & MyData
        Buffer = ""
    End If
End Sub

Private Sub UserForm_Initialize()
    Dim i As Byte
    For i = 1 To 9
        If IsComPortAvailable(i) = True Then
            ComboBox1.AddItem i
        End If
    Next
End Sub

Private Sub UserForm_Terminate()
    'Close serial port on exit
    On Error Resume Next    'Error handler
    
    If NETComm1.PortOpen = True Then    'check if the serial port is open
        NETComm1.PortOpen = False       'close the serial port
    End If
    If Err Then MsgBox Error$, 48     'Display error in message box
    
End Sub
Function IsComPortAvailable(ByVal portNum As Integer) As Boolean
    Dim fnum As Integer
    On Error Resume Next
    fnum = FreeFile
    Open "COM" & CStr(portNum) For Binary Shared As #fnum
    If Err = 0 Then
        Close #fnum
        IsComPortAvailable = True
    End If
End Function



(Arduino程式碼在「利用Excel VBA利用串列埠RS232讀取Arduino資料」)文章內 

請選擇本身電腦Arduino com port

執行畫面:



2018年10月1日 星期一

利用Excel VBA利用串列埠RS232讀取Arduino資料

使用:NetCommOCX

我的電腦係win7 32位元 請至   Updated installer for Windows 7


依NETCommOCX Information Page介紹安裝以系統管理員身分執行Setup.exe








Excel 2007 -->開發人員-->Visual Basic-->






新增一個NETComm1、TextBox1、CommandButton1、CommandButton2

NETComm1的commport記得要填上arduino使用的COM

將下列程式碼複制到VBA程式碼

Private Sub CommandButton1_Click()
    On Error Resume Next
    NETComm1.SThreshold = 1
    NETComm1.RThreshold = 1
    NETComm1.CommPort = 4
    If NETComm1.PortOpen = False Then  'if the serial port is closed
        NETComm1.PortOpen = True       'open the serial port
    End If
    If Err Then MsgBox Error$, 48
End Sub

Private Sub CommandButton2_Click()
    'Close serial port on exit
    On Error Resume Next    'Error handler
    
    If NETComm1.PortOpen = True Then    'check if the serial port is open
        NETComm1.PortOpen = False       'close the serial port
    End If
    If Err Then MsgBox Error$, 48     'Display error in message box
    End
End Sub

Private Sub NETComm1_OnComm()
    Dim d As Date
    Static Buffer As String
    Dim CRLFPos As Integer
    Buffer = Buffer & NETComm1.InputData 'or whatever name you use for the instance of NETComm
    
    CRLFPos = InStr(Buffer, vbCr)
    If CRLFPos > 0 Then
        Dim MyData As String
        d = Now()
        MyData = d & Mid(Buffer, 1, CRLFPos - 1) & vbCrLf
        TextBox1.Text = TextBox1.Text & MyData
        Buffer = ""
    End If
End Sub
Private Sub UserForm_Terminate()
    'Close serial port on exit
    On Error Resume Next    'Error handler
    
    If NETComm1.PortOpen = True Then    'check if the serial port is open
        NETComm1.PortOpen = False       'close the serial port
    End If
    If Err Then MsgBox Error$, 48     'Display error in message box
    
End Sub

Arduino接線圖


Arduino端程式碼

#include <DHT.h>
#define DHTPIN 2    // 設定DHT的接腳
#define DHTTYPE DHT11   // DHT 11 定義DHT的類型為DHT11
//#define DHTTYPE DHT22   // DHT 22  (AM2302), AM2321
DHT dht(DHTPIN, DHTTYPE);
void setup() {
  Serial.begin(9600);
  //Serial.println("DHT11 test!");
  dht.begin(); //啟動DHT
}
 
void loop() {
  // 每次偵測間隔2秒
  char ch=13;
  delay(2000);
  
  //讀取濕度
  float h = dht.readHumidity();
  //讀取攝氏溫度
  float t = dht.readTemperature();
  //讀取華氏溫度
  float f = dht.readTemperature(true);
 
  //檢查是不是有讀到資料
  if (isnan(h) || isnan(t) || isnan(f)) {
    Serial.println("Failed to read from DHT sensor! \n");
    return;
  }
  Serial.print("Humidity:");
  Serial.print(h,1); //顯示到小數點後一位
  Serial.print("%/");
  Serial.print("Temperature:");
  Serial.print(t,1);//顯示到小數點後一位
  Serial.print("C");
  Serial.print(ch);

}

Arduino透過串列埠傳送溫溼度數值給電腦的Excel VBA


2018年7月23日 星期一

Arduino UNO R3 自製Library RS232通訊

參考:葉難Arduino撰寫自已的程式庫如何編寫ARDUINO LIBRARY

將自已寫的Arduino UNO R3 使用自建C函式庫改寫成Library

UART相關設定參考:http://coopermaa2nd.blogspot.com/2011/07/5-usart.html 在arduino\libraries資料夾下新增一個自已的函式庫資料夾RS232


USART 暫存器

UCSR0A 這個暫存器中,比較重要的是 RXC0, TXC0, UDRE0 這三個旗號:

bit7:RXC0: USART Receive Complete,當 receiver buffer 中有未讀取的資料時,這個旗號會豎起來,當資料被讀走時,旗號會清除。

bit6:TXC0: USART Transmit Complete,當 Shift Register 的資料被傳送出去,而且 transmit buffer (UDR0) 中也沒有資料時,這個旗號會豎起來。

bit5:UDRE0: USART Data Register Empty,當 transmit buffer (UDR0) 準備好放下一個要傳送的資料時,這個旗號會豎起來。





while(!(UCSR0A & 0b00100000)){ }//等待bit5變成1,否則一直等待。等待RS232空閒。
void RS232::put_string(char *string) {
   while(*string) { 
            while(!(UCSR0A & 0b00100000)) { } 
            UDR0=*string++; 
   }
 }
while(!(UCSR0A & 0b10000000)){}//等待bit7變成1,否則一直等待。一直等待RS232傳送資料過來。
char RS232::get_char() {
   char recchar;
   while(!(UCSR0A & 0b10000000)){}
   recchar=UDR0;
   put_char(recchar);
   return recchar; 
}


新增一個RS232.h內容如下:

#ifndef RS232_H
#define RS232_H
#include <avr/interrupt.h> 
class RS232 {
public:
 RS232();
 ~RS232();
 void begin(unsigned long baud);
 void put_char(char str);
 void put_string(char *string);
 char get_char(void); 

};
#endif
新增一個RS232.cpp內容如下:
#include <RS232.h>
RS232::RS232(){ 
}
RS232::~RS232(){ 
}
void RS232::begin(unsigned long baud){
    unsigned int baud_setting=(F_CPU/16/baud)-1;
    UBRR0H=(unsigned char)(baud_setting>>8);
    UBRR0L=(unsigned char)baud_setting;
    UCSR0B=0B00011000;//啟用transmitter和receiver,並且不使用中斷。RXEN0=1,TXEN0=1,RXCIE0=0,TXCIE0=0。
    UCSR0C=0B00000110;//設定frame format為N,8,1
}
void RS232::put_string(char *string)
{
    while(*string)
    {
        while(!(UCSR0A & 0b00100000))
        {  }
        UDR0=*string++;
    }
}
void RS232::put_char(char str)
{
       while(!(UCSR0A & 0b00100000))
       {  }
       UDR0=str;
}
char RS232::get_char()
{
 char recchar;
 while(!(UCSR0A & 0b10000000)){}
 recchar=UDR0;
 put_char(recchar);
 return recchar;
}


新增一個檔案keywords.txt內容如下:
RS232 KEYWORD1
begin KEYWORD2
put_char KEYWORD2
put_string KEYWORD2
get_char KEYWORD2
新增一個資料檔案example\rs232_lib.ino內容如下:
#include <RS232.h>
RS232 RS232;
void setup(){
  RS232.begin(9600);
}
void loop(){
  char char_reg;
  char_reg=RS232.get_char();
  RS232.put_char('Z');
  RS232.put_string("Hello World");
}

2018年7月19日 星期四

Arduino UNO R3藍牙實驗 App Inventor2 透過藍牙傳送訊號給 Arduino

參考:[雙A計劃] Part0:App Inventor 透過藍牙傳送訊號給 Arduino

材料清單:
1、Android手機
2、Arduino UNO R3
3、藍芽模組(BT06),請仿照電路圖接線(藍芽RX接Arduino D5、藍芽TX接Arduino D4、藍芽VCC接Arduino 5V、藍芽GND接Arduino GND)




'
接完線依照文章內容打上程式,編輯後上傳到板子上。




#include <SoftwareSerial.h>
#include <Wire.h>  //引用二個函式庫SoftwareSerial及Wire SoftwareSerial 
SoftwareSerial I2CBT(4,5); //定義PIN4及PIN5分別為Arduino RX及TX腳位接藍芽的TX腳位與RX腳位 
void setup() { 
  Serial.begin(9600); //Arduino起始鮑率9600 
  I2CBT.begin(9600); //藍牙鮑率9600
  //(注意!此鮑率每個藍牙晶片不一定相同,請先確認完再填寫進去) 
} 

void loop() { 
  byte cmmd[20]; 
  int insize; 
  while(1){ 
  if ((insize=(I2CBT.available()))>0)
  {  //判斷有沒有訊息接收 
    Serial.print("input size = "); 
    Serial.println(insize);  //顯示接收多少訊息 
    for (int i=0; i<insize; i++) {
      Serial.print(cmmd[i]=char(I2CBT.read()));//將接收的訊息顯示出來
      Serial.println(" ");  
    }//if
  } //for 
  }//while
}






2018年7月18日 星期三

Arduino 藍芽BT06(相容HC06)測試AT指令,行結尾使用NL&CR

BT06從淘寶買來的相容HT06

參考資料:http://coopermaa2nd.blogspot.com/search?q=bluetooth

參考[雙A計劃] Part1:App Inventor 經由藍牙控制 Arduino LED 亮滅做實驗這個實驗電路也很簡單四條線,一開始接完燒錄完程式,手機按BT List沒有反應。最後發現原來手機要開啟藍芽功能,先去連線Arduino的藍芽輸入PIN碼才能使用。

後來參考HC-05與HC-06藍牙模組補充說明(三):使用Arduino設定AT命令去使用裡面的接線,去測試一下我的藍牙模組有沒有反應,一開始輸入AT也是沒有反應,
後來去修改通訊速率一個一個試都沒有反應。有看到HC-06要使用沒有行結尾、HC-05要使用\n\r行結尾。最後設定使用\n\r輸入AT有反應了。

雖然BT-06相容HC-06但行結尾是相容HC-05。

參考[雙A計畫]藍牙模組(HC05、HC06)常見的指令使用教學裡的電路圖接線,用arduino IDE的序列埠監控視窗,行結尾使用NL&CR 。
AT:用於確認通訊。
AT+VERSION:查看韌體版本
AT+NAMEOOOO:設定模組的識別名稱。

AT+PINOOOO:更改配對密碼。假如你不想讓其他人輕易地連接到你的藍牙裝置,可以透過這個AT命令修改配對密碼。



2018年7月9日 星期一

Arduino UNO R3 4×4鍵盤模組實驗

參考:https://swf.com.tw/?p=917

利用Time 1中斷,每0.1秒去掃描看沒有按鍵被按。
Time中斷可參考http://tomyam-yang.blogspot.com/2017/06/arduino-timer-as-counter.html

提升電阻參考https://www.arduino.cc/en/Tutorial/DigitalPins

volatile char key_pad;因為key_pad變數使用在中斷內如果不使用volatile去定義,有可能這一次編譯可以正常執行,下一次編譯卻有問題,詳細說明可參考http://newscienceview.blogspot.com/2013/09/c-volatile.html

將多維陣列keymap[][]傳入副函式scan_key的方法如下:
key_pad=scan_key(KEY_COLS,KEY_ROWS,(char *)keymap,colPins,rowPins);
key_pad=scan_key(KEY_COLS,KEY_ROWS,*keymap,colPins,rowPins);
key_pad=scan_key(KEY_COLS,KEY_ROWS,keymap[0],colPins,rowPins);
key_pad=scan_key(KEY_COLS,KEY_ROWS,&keymap[0][0],colPins,rowPins);

陣列的參數傳遞可以參考C陣列[C++]如何將多維陣列傳入副函式二維陣列與雙重指標之間的關係


char scan_key(byte,byte,char *,byte *,byte *);
#define KEY_ROWS 4 // 按鍵模組的列數
#define KEY_COLS 4 // 按鍵模組的行數
const byte colPins[KEY_COLS] = {9, 8, 7, 6};     // 設定「行」腳位
const byte rowPins[KEY_ROWS] = {13, 12, 11, 10}; // 設定「列」腳位
const char keymap[KEY_ROWS][KEY_COLS] = {
  {'A', '7', '8', '9'},
  {'B', '4', '5', '6'},
  {'C', '1', '2', '3'},
  {'D', 'E', 'F', '0'}
};
volatile char key_pad;
void setup() {
 byte i;
//設定中斷1參數:
  TCCR1A=0x00;
  TCCR1B=0b00000101;//設定除頻1024 15625HZ 
  TCNT1=-1562;      //約0.1秒掃描一次
  TIMSK1 |=0x01;    //啟動Timer中斷

  key_pad=0;
  for ( i = 0; i <= 3; i++) {
    pinMode(rowPins[i], INPUT);
    pinMode(colPins[i], OUTPUT);
    digitalWrite(colPins[i], HIGH);
    digitalWrite(rowPins[i], HIGH);//啟動上拉電阻
  }
  Serial.begin(9600);
}

void loop() {
  while(key_pad)
  {
    Serial.println(key_pad);
    key_pad=0;
  }
}
ISR(TIMER1_OVF_vect)
{
  TIMSK1 &=0xfe;
  key_pad=scan_key(KEY_COLS,KEY_ROWS,(char *)keymap,colPins,rowPins);
  TCNT1=-1562;
  TIMSK1 |=0x01;
 }
 
char scan_key(byte col,byte row,char *key_map,byte *col_pin,byte *row_pin)
{
  unsigned long time_;
  byte i,j;
  byte scanVal;   // 暫存掃描到的按鍵值low or high
  time_=millis();
  for (i = 0; i < row; i++) { //按著不放的情況下不用理它
    scanVal=digitalRead(*(row_pin+i));
    if (scanVal == LOW)
    {
      return 0;   
    }
  }
  for (i = 0; i < row; i++) {
    for (j = 0; j < col; j++) {
      digitalWrite(*(col_pin+j),LOW);
      scanVal=digitalRead(*(row_pin+i));
      if (scanVal == LOW) {    // 如果輸入值是「低電位」…      
        for(;;)
        {
          if((millis()-time_)>1000)
          {
            return 0;
          }
          delay(100);
          scanVal=digitalRead(*(row_pin+i));
          if (scanVal == LOW)
          {
            return *(key_map+i*row+j);
          }
        }
      }
      digitalWrite(*(col_pin+j),HIGH);    
    }
  }
  return 0;
 }

2018年7月5日 星期四

Arduino UNO R3 使用自建C函式庫

參考資料:https://arduino.stackexchange.com/questions/946/how-to-call-c-functions-from-arduino-sketch

UART的使用可以參考http://tomyam-yang.blogspot.com/2017/06/arduino-timer-as-counter.html


要在arduino主程式使用c函式庫,需要把函式庫放在arduino/libraries資料夾下。


並在主程式使用extern "C"{} include 函式


我在libraries底下建一個資料夾放我的.c與.h檔,分別是io.h、iom328p.h、serial.c、serial.h


io.h與iom328p.h是內建的,是定義arduino uno r3的參數,但當你使用自建c函式庫驗證會找不到,所以就把它放進來同一個資料夾內。


底下的程式是自建uart程式,bitrate:9600。

主要副程式

void uart9600_setup(); //初始設定

void serial_put(char *string); //輸出字串

char serial_get(void);//取的字元

void serial_putchar(char string);//輸出字元

主程式:


extern "C"{
#include <serial.h>
}
char rechchar;
char message[]="Hello World";
void setup() {
  // put your setup code here, to run once:
  uart9600_setup();
  serial_put(message);
}

void loop() {
    rechchar=serial_get();
}
serial.c

#include <iom328p.h>
#include <io.h>
void serial_put(char *string)
{
   while(*string)
   {
      while(!(UCSR0A & 0b00100000))
      {  }
      UDR0=*string++;
   }
}
void serial_putchar(char string)
{

      while(!(UCSR0A & 0b00100000))
      {  }
      UDR0=string;
}
char serial_get()
{
  char recchar;
  while(!(UCSR0A & 0b10000000))
  {

  }
  recchar=UDR0;
  //UDR0=*recchar;
  serial_putchar(recchar);
  return recchar;
}
void uart9600_setup()
{
   //unsigned int baud_setting=103;
   UBRR0H=(unsigned char)0;
   UBRR0L=(unsigned char)103;
   UCSR0B=0B00011000;//啟動接收中斷、啟動傳送接收
   UCSR0C=0B00000110;
}
ISR(USART_RX_vect)
{
  char ReceivedChar;
  ReceivedChar=UDR0;
  UDR0=ReceivedChar;
}
serial.h


void uart9600_setup();

void serial_put(char *string);

char serial_get(void);

void serial_putchar(char string);


















2018年7月4日 星期三

Arduino UNO LCD 2004A I2C

參考資料:https://makerpro.cc/2017/02/how-arduino-use-i2c-to-control-lcd-module/

這個看起來很簡單只需接四條線,也有範例程式,但花了我快一個星期才試好。最後發現是LCD出廠把光源調到最亮,字才會跑不出來。最後也是去購買的拍賣看到留言才知道問題。
參考資料用的I2C位址係0x27,因我使用的LCD I2C晶片不一樣所以不同。
可以參考https://docs.labs.mediatek.com/resource/linkit7697-arduino/en/tutorial/driving-1602-lcd-with-pcf8574-pcf8574a

PCF8574A這個IC的位址0X3f
PCF8574這個IC的位址0X27
#include <LiquidCrystal_I2C.h>
#define I2C_ADDR    0x3f  // 定義I2C使用PCF8574A這個IC的位址
// 其實位址可以利用A0,A1或A2改變
// 定義LiquidCrystal函式庫裡LCD各個腳位
#define BACKLIGHT_PIN 3
#define En_pin  2
#define Rw_pin  1
#define Rs_pin  0
#define D4_pin  4
#define D5_pin  5
#define D6_pin  6
#define D7_pin  7
LiquidCrystal_I2C lcd(I2C_ADDR,En_pin,Rw_pin,Rs_pin,D4_pin,D5_pin,D6_pin,D7_pin,BACKLIGHT_PIN, POSITIVE);
void setup() {
  lcd.begin(20,4);        // 4行,每行20個字
  lcd.setBacklight(HIGH); // 開啟LCD背光,要關閉就用LOW
  lcd.setCursor ( 0, 0 );            // 到第一行第一個字
  lcd.print("hello, world!");
}
 int n = 1; // 顯示LCD刷新次數
 void loop() {
  lcd.noCursor();
  lcd.setCursor (16,3);         // 到第四行的第16個字元
  lcd.print(n++,DEC);           // 更新次數
                                // 覆蓋前一個數字
  delay(500);                   // 等待半秒鐘後更新
  lcd.cursor();
  delay(500);
}

2017年6月17日 星期六

Arduino Time2 中斷計時微秒

參考資料:
http://coopermaa2nd.blogspot.tw/2011/07/4-timers.html
http://coopermaa2nd.blogspot.tw/2011/07/41-blink-with-timer.html

利用time2除頻256 16MHZ 剩62500HZ 1clok要0.000016秒 1ms需62.5個clock約63 63clok=0.001008秒
time2除頻與time0、time1不一樣
CS22 CS21 CS20 功能
0 0 0 停止
0 0 1 clk/1
0 1 0 clk/8
0 1 1 clk/32
1 0 0 clk/64
1 0 1 clk/128
1 1 0 clk/256
1 1 1 clk/1024
volatile unsigned int delay_ms_count;
void delay_ms(unsigned int i);
void setup() {
  // put your setup code here, to run once:
DDRB=0b00100000;//設定P13為output
TCCR2A=0x00;
TCCR2B=0b00000110;//設定除頻256
TCNT2=-63;
}
void loop() {
 // put your main code here, to run repeatedly:
 //設定P13 hight
 PORTB =PORTB | 0B00100000;
 delay_ms(1000);
 //設定P13 low
 PORTB=PORTB & 0B11011111;
 delay_ms(1000);
}
void delay_ms(unsigned int i)
{
  delay_ms_count=i;
  TCNT2=-63;
  TIMSK2 |=0x01;//啟動中斷time2
  while(delay_ms_count > 0){
  }
  TIMSK2 &=0xfe;//關閉中斷time2
}
ISR(TIMER2_OVF_vect)
{
 delay_ms_count--;
 TCNT2=-63;
}

2017年6月16日 星期五

Arduino Timer as a Counter

void uart9600_setup();
void serial_put(char *string);
void num2str(int i,char *a);
char nu2ch[3];
TCCRxA – Timer/Counter Control Register A (x 代表 0, 1 或 2):
TCCRxA 暫存器主要是用來設定 Timer 的模式,例如 PWM 輸出等進階的功能。一般來說,如果沒用到 PWM,只是要單純的 Timer/Counter 功能的話,
那麼把 TCCR0A 暫存器設定成 0x00 就行了。

TCCRxB – Timer/Counter Control Register B:
TCCR1B 暫存器主要是用來設定 clock source。比較重要的是 CS12、CS11 和 CS10 這三個位元,這三個元位就是用來選擇 clock 的
TCNTx – Timer/Counter Register:
TCNTx 暫存器比較簡單,它就是 Timer 的計數器。
void setup() {
  // put your setup code here, to run once:
  //Serial.begin(9600);
  uart9600_setup();
  TCCR1A=0x00;
  TCCR1B |=_BV(CS12);
  TCCR1B |=_BV(CS11);
  TCCR1B |=_BV(CS10);
  TCNT1=0;

}
   void loop() {
   serial_put("TCNT1:");
   num2str(TCNT1,nu2ch); 
   serial_put(nu2ch);
   serial_put("\n");
   delay(1000);
}
  
void num2str(int i,char *a)
{
  unsigned char t,h,z;
  if (i>999)
  {
    i=0;
  }
  else
  {
    t=(i/100);
    h=(i-t*100)/10;
    z=(i-t*100-h*10);
    a[2]=z+48;
    a[3]='\0';
    if (t==0)
    {
      *a=' ';
      if(h==0)
      {
        a[1]=' ';
      }
      else
      {
        a[1]=h+48;
      }
    }
    else
    {
      *a=t+48;
      a[1]=h+48;
    }
  }
}
UCSR0A – USART Control and Status Register A: 在 UCSR0A 這個暫存器中,比較重要的是 RXC0, TXC0, UDRE0 這三個旗號:
bit7 RXC0: USART Receive Complete,當 receiver buffer 中有未讀取的資料時,這個旗標會變1,當資料被讀走時,旗標會變0。
bit6 TXC0: USART Transmit Complete,當 Shift Register 的資料被傳送出去,而且 transmit buffer (UDR0) 中也沒有資料時,這個旗標會變1。
bit5 UDRE0: USART Data Register Empty,當 transmit buffer (UDR0) 準備好放下一個要傳送的資料時,這個旗標變1。

UDR0 – USART I/O Data Register 0:
UDR0 暫存器比較簡單,它是用來放資料的暫存器。比較特別的是,transmitter 跟 receiver 共用 UDR0 暫存器。不過,對 UDR0 寫資料其實是放到 TXB 暫存器,而讀取 UDR0 時資料則是從 RXB 暫存器中取出。
 
void serial_put(char *string)//傳送字串
{
   while(*string)
   {
      while(!(UCSR0A & 0b00100000)) //判斷UDRE0是否已經準備好要傳送下一個char
      {  }
      UDR0=*string++;//UDR0=*string;*string=*string+1;
   }
}

UBRR0L 和 UBRR0H – USART Baud Rate Registers: UBRR0H[11:8]
UBRR0L[7:0]
這兩個暫存器是用來設定 Baud Rate 的,公式是:
設定值 = (F_CPU/16/baud rate) – 1
其中 F_CPU 代表時脈頻率,以 Arduino UNO 而言是 16000000,baud rate 是想要的速率,例如 9600, 19200, 38400, 57600… 等。

UCSR0B – USART Control and Status Register B:
RXCIE0, TXCIE0, UDRIE0 則是用來決定要不要啟用中斷的位元:
bit7 RXCIE0: USART Receive Complete Interrupt Enable 0
bit6 TXCIE0: USART Transmit Complete Interrupt Enable 0
bit5 UDRIE0: USART Data Register Empty Interrupt Enable 0
bit4 RXEN0 接收器旗標 0:關閉 1:啟用
bit3 TXEN0 發射器旗標 0:關閉 1:啟用

UCSR0C – USART Control and Status Register C:
UCSR0C 是用來設定通訊所用的 Frame format (訊框格式),比如同步/非同步傳輸, Parity, Stop bit 及 Data bits 等設定:
相關設定可以參考http://coopermaa2nd.blogspot.tw/2011/07/5-usart.html
 
void uart9600_setup()
{
   //UART初始設定9600 n,8,1
   //ubrr 設定值 = (F_CPU/16/baud rate) – 1
   //ubrr=16000000/16/9600-1=103
   UBRR0H=(unsigned char)0;
   UBRR0L=(unsigned char)103;
   UCSR0B=0B00011000;//啟動接收中斷、啟動傳送接收
   UCSR0C=0B00000110;//usart control and status register c n,8,1
}
參考: http://coopermaa2nd.blogspot.tw/2011/07/42-timer-as-counter.html

材料:
開關 1個
電阻10K 1個

接線圖



























實驗結果