Hướng dẫn lập trình Module Sim M95 và Arduino

Xin chào các bạn, bài viết hôm nay hướng dẫn các bạn cách lập trình để giao tiếp với Module Sim Quectel M95 và Arduino Uno R3.

Bài thực hành: điều khiển bật/tắt thiết bị thông qua cuộc gọi (DTMF) 

Trước tiên liệt kê một vài lệnh thông dụng

1.Lệnh chung

Lệnh:      AT<CR><LF>

Trả lời:   OK<CR><LF>

Mô tả : Kiểm tra đáp ứng của Module M95 Sim , nếu trả về OK thì Module hoạt động

 

Lệnh:      ATE[x]<CR><LF>

Trả lời:   OK<CR><LF>

Mô tả : Chế độ echo là chế độ phản hồi dữ liệu truyền đến của module Sim M95,

x = 1 bật chế độ echo , x = 0 tắt chế độ echo (bạn nên tắt chế độ này)

 

Lệnh:      AT+IPR=[baud rate]<CR><LF>

Trả lời:   OK<CR><LF>

Mô tả : cài đặt tốc độ giao tiếp dữ liệu với module Sim M95, chỉ cài được các tốc độ sau

baud rate :    0  (auto), 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200

 

2.Lệnh điều khiển cuộc gọi

Lệnh:      ATD[Số_điện_thoại];<CR><LF>

Trả lời:   OK<CR><LF>

Mô tả : Lệnh thực hiện cuộc gọi

 

Lệnh:      ATH<CR><LF>

Trả lời:   OK<CR><LF>

Mô tả : Lệnh thực hiện kết thúc cuộc gọi , hoặc cúp máy khi có cuộc gọi đến

Lệnh:      ATA<CR><LF>

Trả lời:   OK<CR><LF>

Mô tả : Lệnh thực hiện chấp nhận khi có cuộc gọi đến

Chú ý: khi nhân được cuộc gọi đến thì Module Sim M95 sẽ phản hồi về như sau

    RING

    RING

Nếu muốn hiển thị thông tin người gọi đến các bạn thực hiên thêm lệnh sau

Lệnh:      AT+CLIP=1<CR><LF>

Trả lời:   OK<CR><LF>

 

3.Lệnh điều khiển tin nhắn

Lệnh:      AT+CMGF=1<CR><LF>

Trả lời:   OK<CR><LF>

Mô tả : Lệnh đưa SMS về chế độ Text , phải có lệnh này mới gửi nhận tin nhắn dạng Text

 

Cấu trúc gửi tin nhắn

Lệnh:      AT+CMGS=”Số_điện _thoại”<CR><LF>

Đợi đến khi có ký tự ‘>’ được gửi về

Gửi nội dụng tin nhắn : “This is a test

Gửi mã Ctrl+Z  hay  0x1A để kết thúc nội dung và gửi tin nhắn

Trả lời :  OK<CR><LF>

 

Lệnh:      AT+CMGR=1<CR><LF>

Mô tả : Đọc một nhắn vừa gửi đến, lệnh được trả về nội dung tin nhắn, thông tin người gửi, thời gian gửi

Chú ý: Nếu Module Sim M95 nhận được một tin nhắn bất kỳ, thì nó gửi về cụm “+CMTI” để thông báo

Trong trường hợp bạn muốn hiển thị trực tiếp nội dung tin nhắn(không lưu vào bộ nhớ của sim) bạn gửi lệnh sau

AT+CNMI=2,2<CR><LF>

 

4.Lệnh DTMF

 

Giới thiệu về DTMF

DTMF (Dual tone multi frequency): Dùng trong lĩnh vực viễn thông, ứng dụng giám sát, điều khiển thông minh.

Ví dụ ứng dụng trong liên lạc tổng đài: khi bạn gọi lên tổng đài, tổng đài yêu cầu bạn ấn phím để chọn chức yêu cầu tương ứng, vậy tổng đài làm sao biết bạn ấn phím gì, 

Khi bạn ấn phím (trong quá trình gọi) thì sẽ phát ra một tiếng kêu đặc biệt gọi là "DTMF Tone" (mỗi phím ấn sẽ có DTMF Tone khác nhau) dựa vào xác định đặc điểm DTMF Tone nhận được, tổng đài biết ta ấn phím nào phím nào

Mỗi DTMF Tone kết hợp bởi hai tần số: Low frequency và High frequency (vì thế gọi dual tone)

Ví dụ khi bạn ấn phím "1" sẽ phát ra hai tần số: Low frequency 697Hz và High frequency 1209Hz

Các bạn có thể xem bảng dưới để thấy chi tiết hơn

So với điều khiển qua tin nhắn(SMS) hay qua mạng (GPRS) thì dùng DTMF đơn giản hơn khá nhiều, thao tác nhanh gọn hơn.

Nhiều module sim trên thị trường không tích hợp bộ giải mã DTMF bên trong, khi muốn dùng điều khiển qua cuộc gọi thì cần mạch giải mã DTMF bên ngoài . Với M95 ta không cần làm điều đó, nó đã được tích hợp sẵn, giao tiếp qua lệnh AT

 

Lệnh:      AT+QTDMOD =1,0<CR><LF>

Trả lời:   OK<CR><LF>

Mô tả :   Lệnh cho phép phát hiện tất cả DTMF

 

Lệnh:      AT+QTONEDET =1<CR><LF>

Trả lời:   OK<CR><LF>

Mô tả :   Cho phép giải mã DTMF

 

Sau khi đã cấu hình xong

Chờ đến khi có cuộc gọi đến, gửi ATA<CR><LF> để bắt cuộc gọi.

Trong quá trình bắt cuộc gọi, nếu đầu máy bên kia thao tác các phím thì Module Sim Quectel M95 sẽ nhận được thông tin tương ứng với phím nào được ấn

+QTONEDET: 48          // ấn phím 0

+QTONEDET: 49          // ấn phím 1

+QTONEDET: 50          // ấn phím 2

+QTONEDET: 51          // ấn phím 3

+QTONEDET: 52          // ấn phím 4

+QTONEDET: 53          // ấn phím 5

+QTONEDET: 54          // ấn phím 6

+QTONEDET: 55          // ấn phím 7

+QTONEDET: 56          // ấn phím 8

+QTONEDET: 57          // ấn phím 9

+QTONEDET: 42          // ấn phím *

+QTONEDET: 35          // ấn phím #

 

Bây giờ chúng ta đi thực hành: điều khiển bật/tắt thiết bị thông qua cuộc gọi dùng DTMF

Chuẩn bị phần cứng:

1 Kit Arduino Uno hoặc 1 Kit Unovn01

http://mlab.vn/1697809-uno-vn01-arduino-uno-phien-ban-viet-nam.html

http://mlab.vn/407044-arduino-uno-r3-su-dung-atmega-328p-pu.html

1 Module Sim Quectel M95 dùng cho Arduino

http://mlab.vn/1247689-m95-shield-su-dung-voi-arduino.html

1 Module DI + Relay Shield

http://mlab.vn/1713481-di-relay-shield.html

1 Nguồn 12V/1A

http://mlab.vn/1272384-adapter-dc-12v-1a.html

Bạn nên chuẩn bị một thiết bị tải như bóng đèn.

Sơ đồ kết nối

Dưới đây là code tham khảo:

Thực hiện điều khiển đóng cắt Relay, khi có cuộc gọi đến tự động bắt máy,

Người dùng ấn Phím 1: Bật Relay

Người dùng ấn phím 4: Tắt Relay

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

int PWK_PIN = 9;                // Khai báo chân điều khiển bật/tắt module SimM95
int RELAY1_PIN = 2;         //  Khai bao chân điều khiển relay
int RELAY2_PIN = 3;
 
#define PWK_HIGH    digitalWrite(PWK_PIN, HIGH)
#define PWK_LOW     digitalWrite(PWK_PIN, LOW)
 
#define RELAY1_ON   digitalWrite(RELAY1_PIN, LOW)
#define RELAY1_OFF  digitalWrite(RELAY1_PIN, HIGH)
 
#define RELAY2_ON   digitalWrite(RELAY2_PIN, LOW)
#define RELAY2_OFF  digitalWrite(RELAY2_PIN, HIGH)
 
char respond[100];            // khai báo bộ đệm lưu dữ liệu
char gsmdata[100];
int  gsmdata_write = 0;
 
void SimM95_Init(void);                         // Hàm cấu hình SimM95
 
int readSerialFrame(char result[]);       // Hàm đọc dữ liệu nhận về từ Module SimM95
 
void Clear_gsmdata(void);                    // Hàm xóa dữ liệu của bộ đệm
 
void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);                               // Cấu hình UART để giao tiếp Module SimM95
  Clear_gsmdata();
  
  pinMode(PWK_PIN, OUTPUT);          // Cấu hình chân PWK điều khiển bật tắt Module SimM95
  PWK_LOW;
 
  pinMode(RELAY1_PIN, OUTPUT);   // Cấu hình chân điều khiển Relay
  RELAY1_OFF;
 
  pinMode(RELAY2_PIN, OUTPUT);
  RELAY2_OFF;
  SimM95_Init();
}
 
void loop() {
  // put your main code here, to run repeatedly:
  static int SimM95_Call = 0;
  if(SimM95_Call == 0)
  {
    if(strstr(gsmdata,"\r\nRING\r\n") != NULL)                // Kiểm tra có cuộc gọi hay không
    {
      Clear_gsmdata();
          
      Serial.write("ATA\r\n");                                               // Nếu có thì gửi lệnh bắt máy (Bạn xem lại tập lệnh để rõ hơn)
      delay(1000);
      if(readSerialFrame(respond) > 0)                          
      {
        if(strstr(respond,"\r\nOK\r\n") != NULL)
        {
          SimM95_Call = 1;
        }
      }
    }
  }
  else if(SimM95_Call == 1)
  {
    if(strstr(gsmdata,"\r\n+QTONEDET: 49\r\n") != NULL)    // Kiểm tra phím 1 ấn hay ko          
    {
       RELAY1_ON;                                                                     // Nếu có thì bật Relay
       Serial.write("ATH\r\n");                                                     // Tự động tắt máy
       delay(1000);
       if(readSerialFrame(respond) > 0)
       {
         if(strstr(respond,"\r\nOK\r\n") != NULL)
         {
           SimM95_Call = 0;
         }
       }
    }
    else if(strstr(gsmdata,"\r\n+QTONEDET: 52\r\n") != NULL)   // Kiểm tra phím 4 ấn hay không
    {
       RELAY1_OFF;                                                                           // Nếu có tắt Relay
       Serial.write("ATH\r\n");                                                             // Tư động tắt máy
       delay(1000);
       if(readSerialFrame(respond) > 0)
       {
         if(strstr(respond,"\r\nOK\r\n") != NULL)
         {
           SimM95_Call = 0;
         }
       }
    }
    else if(strstr(gsmdata,"\r\nNO CARRIER\r\n") != NULL)      // Kiểm tra người dùng có tắt máy hay không
    {
       SimM95_Call = 0;
    }
  }
}
 
void SimM95_Init(void)
{
  static bool SimM95_Init_Ok = false;
  if(SimM95_Init_Ok == false)
  {
    try_on:
    PWK_LOW;
    delay(2000);
    PWK_HIGH;
    delay(2000);
    PWK_LOW;
    delay(5000); 
 
    Serial.write("AT\r\n");
    delay(1000);
    if(readSerialFrame(respond) > 0)
    {
      if(strstr(respond,"\r\nOK\r\n") == NULL)
      {
        goto try_on;
      }
    }
    else
    {
      goto try_on;
    } 
    
    Serial.write("ATE0\r\n");
    delay(1000);
    if(readSerialFrame(respond) > 0)
    {
      if(strstr(respond,"\r\nOK\r\n") == NULL)
      {
        goto try_on;
      }
    }
    else
    {
      goto try_on;
    } 
 
    Serial.write("AT+IPR=9600\r\n");
    delay(1000);
    if(readSerialFrame(respond) > 0)
    {
      if(strstr(respond,"\r\nOK\r\n") == NULL)
      {
        goto try_on;
      }
    }
    else
    {
      goto try_on;
    }
 
    Serial.write("AT+CMGF=1\r\n");
    delay(1000);
    if(readSerialFrame(respond) > 0)
    {
      if(strstr(respond,"\r\nOK\r\n") == NULL)
      {
        goto try_on;
      }
    }
    else
    {
      goto try_on;
    }
 
    Serial.write("AT+QTDMOD =1,0\r\n");
    delay(1000);
    if(readSerialFrame(respond) > 0)
    {
      if(strstr(respond,"\r\nOK\r\n") == NULL)
      {
        goto try_on;
      }
    }
    else
    {
      goto try_on;
    }
 
    Serial.write("AT+QTONEDET =1\r\n");
    delay(1000);
    if(readSerialFrame(respond) > 0)
    {
      if(strstr(respond,"\r\nOK\r\n") == NULL)
      {
        goto try_on;
      }
    }
    else
    {
      goto try_on;
    }
    SimM95_Init_Ok = true;
    RELAY2_ON;
  }
}
 
int readSerialFrame(char result[]) 
{
  int i = 0;
  unsigned long currentMillis, previousMillis;
  previousMillis = millis();
  currentMillis = previousMillis;
  while (1) 
  {
    if (currentMillis - previousMillis >= 50) 
    {
      return i;
    }
    else
    {
      if (Serial.available() > 0) {
        previousMillis = currentMillis;
        char inChar = Serial.read();
        result[i] = inChar;
        i++;
        result[i] = 0;      
      }
    }
    currentMillis = millis();
  }
}
 
void serialEvent() {
  while (Serial.available()) {
    // get the new byte:
    char inChar = (char)Serial.read();
    // add it to the inputString:
    gsmdata[gsmdata_write] = inChar;
    gsmdata_write ++;
    if(gsmdata_write >= 100)
    {
      gsmdata_write = 0;
    }
  }
}
 
void Clear_gsmdata(void)
{
  int i = 0;
  for( i = 0; i < 100 ; i ++)
  {
    gsmdata[i] = ' ';
  }
  gsmdata_write = 0;
}
 
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 

Video hướng dẫn

 

Chúc các bạn thành công

Phạm Xuân Lập - MLAB

Viết đánh giá

Họ và tên:


Đánh giá của bạn: Lưu ý: Không hỗ trợ HTML!

Bình chọn: Dở            Hay

Nhập mã bảo vệ: