Translate

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);
}