Thứ Năm, 29 tháng 11, 2018

PIC18F4550 GPRS TCPClient

Giới thiệu

Modul sim 900a
SIM900 cho phép GPRS vào các ứng dụng nhúng. Chúng ta có thể thực hiện giao thức TCP Client bằng cách sử dụng các lệnh AT của SIM900.
Giao thức điều khiển truyền tải (TCP) là giao thức internet tầng giao vận tiêu chuẩn được sử dụng trong việc thiết lập và duy trì giao tiếp giữa máy chủ và máy khách.
Nó được sử dụng rộng rãi trong các ứng dụng nhúng IoT (Internet of Things), nơi mọi cảm biến được kết nối với một máy chủ và chúng tôi có quyền truy cập để kiểm soát chúng qua internet.

Sơ đồ
TCP Client thực hiện bằng cách interfacing PIC18F4550 với SIM900 GPRS
PIC18F4550 với mô-đun SIM900 GSM

TCP Client qua GPRS

Hãy lập trình PIC18F4550 để cấu hình SIM900A như TCP Client và gửi / nhận dữ liệu đến / từ máy chủ bằng GPRS.
Ở đây, chúng tôi đang sử dụng máy chủ Thingspeak cho mục đích demo TCP Client.
Thingspeak là một nền tảng IoT mở, nơi mọi người có thể trực quan hóa và phân tích dữ liệu trực tiếp từ thiết bị cảm biến của họ. Ngoài ra, chúng tôi có thể thực hiện phân tích dữ liệu trên dữ liệu được đăng bởi các thiết bị từ xa với mã Matlab trong Thingspeak. Để tìm hiểu thêm về Thingspeak, hãy tham khảo liên kết https://thingspeak.com/pages/learn_more
Chỉ cần đăng ký và tạo kênh. Chúng tôi có một kênh dưới đây và viết khóa trên Thingspeak để gửi và nhận dữ liệu.
  • ID kênh là = 119922
  • Phím viết = C7JFHZY54GLCJY38
Lưu ý : Đừng quên đánh dấu chọn Make Public field trong cài đặt kênh tùy chọn trên kênh Thingspeak của bạn. Nó làm cho kênh có sẵn để sử dụng như công khai.
Đối với TCP RECEIVE việc sử dụng bên dưới các bước lệnh AT được hiển thị trong ảnh chụp màn hình của Thiết bị đầu cuối RealTermSerial.
Ảnh chụp màn hình bên dưới bao gồm các lệnh AT (Xanh lục) và Phản hồi (Màu vàng).
Phản hồi đã nhận của TCP
Phản hồi đã nhận của TCP

Đối với phương thức TCP SEND, sử dụng các bước lệnh AT được hiển thị trong ảnh chụp màn hình của RealTermSerial Terminal.
Lệnh TCP SEND

Trong chương trình dưới đây của TCP Client, hãy làm như sau
Đối với bản demo TCP Client RECEIVE
#define RECEIVE_DEMO   /* Define Receive demo */
//#define SEND_DEMO   /* Define Send demo */
Đối với bản giới thiệu TCP Client SEND
//#define RECEIVE_DEMO   /* Define Receive demo */
#define SEND_DEMO   /* Define Send demo */
Chỉnh sửa các trường bên dưới với dữ liệu tương ứng
/* Define Required fields shown below */
#define DOMAIN    "api.thingspeak.com"
#define PORT    "80"
#define API_WRITE_KEY   "C7JFHZY54GLCJY38"
#define CHANNEL_ID   "119922"
#define APN    "internet"
#define USERNAME   ""
#define PASSWORD   ""

Trong chương trình dưới đây, chúng tôi đang sử dụng các hàm dựa trên phản hồi để có được trạng thái tốt hơn nếu mọi thứ lệch khỏi bình thường.

Chương trình cho TCP Client

/* 
 * TCP Client using GPRS & PIC
 */

#include <string.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdbool.h>
#include <pic18f4550.h>
#include "USART_Header_File.h"
#include "Configuration_header_file.h"

#define DEFAULT_BUFFER_SIZE  200
#define DEFAULT_TIMEOUT   20000
#define DEFAULT_CRLF_COUNT  2

/* Select Demo */
#define RECEIVE_DEMO   /* Define RECEIVE demo */
//#define SEND_DEMO   /* Define SEND demo */

/* Define Required fields shown below */
#define DOMAIN    "api.thingspeak.com"
#define PORT    "80"
#define API_WRITE_KEY   "C7JFHZY54GLCJY38"
#define CHANNEL_ID   "119922"

#define APN    "internet"
#define USERNAME   ""
#define PASSWORD   ""

enum SIM900_RESPONSE_STATUS {
 SIM900_RESPONSE_WAITING,
 SIM900_RESPONSE_FINISHED,
 SIM900_RESPONSE_TIMEOUT,
 SIM900_RESPONSE_BUFFER_FULL,
 SIM900_RESPONSE_STARTING,
 SIM900_RESPONSE_ERROR
};

int8_t Response_Status, CRLF_COUNT = 0;
uint16_t Counter = 0;
uint32_t TimeOut = 0;
char RESPONSE_BUFFER[DEFAULT_BUFFER_SIZE];
char CONNECTION_NUMBER[] = "1";

void MSdelay(unsigned intval)
{
     unsigned inti,j;
 for(i = 0; i<= val; i++)
 for(j = 0; j < 165; j++);               /* 1 ms delay for 8MHz Frequency */
}

void Read_Response()
{
  char CRLF_BUF[2];
  char CRLF_FOUND;
  uint32_t TimeCount = 0, ResponseBufferLength;
  while(1)
  {
      if(TimeCount>= (DEFAULT_TIMEOUT+TimeOut))
    {
 CRLF_COUNT = 0; TimeOut = 0;
 Response_Status = SIM900_RESPONSE_TIMEOUT;
 return;
    }
    if(Response_Status == SIM900_RESPONSE_STARTING)
    {
 CRLF_FOUND = 0;
 memset(CRLF_BUF, 0, 2);
 Response_Status = SIM900_RESPONSE_WAITING;
    }
    ResponseBufferLength = strlen(RESPONSE_BUFFER);
    if (ResponseBufferLength)
    {
 MSdelay(1);
 TimeCount++;
 if (ResponseBufferLength==strlen(RESPONSE_BUFFER))
 {
     for (uint16_t i=0;i<ResponseBufferLength;i++)
  {
     memmove(CRLF_BUF, CRLF_BUF + 1, 1);
     CRLF_BUF[1] = RESPONSE_BUFFER[i];
     if(!strncmp(CRLF_BUF, "\r\n", 2))
      {
   if(++CRLF_FOUND == (DEFAULT_CRLF_COUNT+CRLF_COUNT))
   {
            CRLF_COUNT = 0; TimeOut = 0;
     Response_Status = SIM900_RESPONSE_FINISHED;
     return;
   }
      }
  }
     CRLF_FOUND = 0;
   }
      }
      MSdelay(1);
      TimeCount++;
   }
}

void Buffer_Flush()
{
 memset(RESPONSE_BUFFER,0,DEFAULT_BUFFER_SIZE);
 Counter = 0;
}

void Start_Read_Response()
{
 Response_Status = SIM900_RESPONSE_STARTING;
 do {
  Read_Response();
 } while(Response_Status == SIM900_RESPONSE_WAITING);
}

void GetResponseBody(char* Response, uint16_t ResponseLength)
{

 uint16_t i = 12;
 char buffer[5];
 while(Response[i] != '\r')
 ++i;

 strncpy(buffer, Response + 12, (i - 12));
 ResponseLength = atoi(buffer);

 i += 2;
 uint16_t tmp = strlen(Response) - i;
 memcpy(Response, Response + i, tmp);

 if(!strncmp(Response + tmp - 6, "\r\nOK\r\n", 6))
 memset(Response + tmp - 6, 0, i + 6);
}

bool WaitForExpectedResponse(const char* ExpectedResponse)
{
 Buffer_Flush();
 MSdelay(200);
 Start_Read_Response();  /* First read response */
 if((Response_Status != SIM900_RESPONSE_TIMEOUT) && 
 (strstr(RESPONSE_BUFFER, ExpectedResponse) != NULL))
 return true;   /* Return true for success */
 return false;   /* Else return false */
}

bool SendATandExpectResponse(const char* ATCommand, const char* ExpectedResponse)
{
 USART_SendString(ATCommand); /* Send AT command to SIM900 */
 USART_TxChar('\r');
 return WaitForExpectedResponse(ExpectedResponse);
}

bool TCPClient_ApplicationMode(uint8_t Mode)
{
 char _buffer[20];
 sprintf(_buffer, "AT+CIPMODE=%d\r", Mode);
 _buffer[19] = 0;
 USART_SendString(_buffer);
 return WaitForExpectedResponse("OK");
}

bool TCPClient_ConnectionMode(uint8_t Mode)
{
 char _buffer[20];
 sprintf(_buffer, "AT+CIPMUX=%d\r", Mode);
 _buffer[19] = 0;
 USART_SendString(_buffer);
 return WaitForExpectedResponse("OK");
}

bool AttachGPRS()
{
 USART_SendString("AT+CGATT=1\r");
 return WaitForExpectedResponse("OK");
}

bool SIM900_Start()
{
 for (uint8_t i=0;i<5;i++)
 {
  if(SendATandExpectResponse("ATE0","OK")||SendATandExpectResponse("AT","OK"))
  return true;
 }
 return false;
}

bool TCPClient_Shut()
{
 USART_SendString("AT+CIPSHUT\r");
 return WaitForExpectedResponse("OK");
}

bool TCPClient_Close()
{
 USART_SendString("AT+CIPCLOSE=1\r");
 return WaitForExpectedResponse("OK");
}

bool TCPClient_Connect(const char* _APN, const char* _USERNAME, const char* _PASSWORD)
{

 USART_SendString("AT+CREG?\r");
 if(!WaitForExpectedResponse("+CREG: 0,1"))
 return false;

 USART_SendString("AT+CGATT?\r");
 if(!WaitForExpectedResponse("+CGATT: 1"))
 return false;

 USART_SendString("AT+CSTT=\"");
 USART_SendString(_APN);
 USART_SendString("\",\"");
 USART_SendString(_USERNAME);
 USART_SendString("\",\"");
 USART_SendString(_PASSWORD);
 USART_SendString("\"\r");
 if(!WaitForExpectedResponse("OK"))
 return false;

 USART_SendString("AT+CIICR\r");
 if(!WaitForExpectedResponse("OK"))
 return false;

 USART_SendString("AT+CIFSR\r");
 if(!WaitForExpectedResponse("."))
 return false;

 USART_SendString("AT+CIPSPRT=1\r");
 return WaitForExpectedResponse("OK");
}

bool TCPClient_connected() {
 USART_SendString("AT+CIPSTATUS\r");
 CRLF_COUNT = 2;
 return WaitForExpectedResponse("CONNECT OK");
}

uint8_t TCPClient_Start(const char* Domain, const char* Port)
{
 USART_SendString("AT+CIPMUX?\r");
 if(WaitForExpectedResponse("+CIPMUX: 0"))
 USART_SendString("AT+CIPSTART=\"TCP\",\"");
 else
 {
  USART_SendString("AT+CIPSTART=\"");
  USART_SendString(CONNECTION_NUMBER);
  USART_SendString("\",\"TCP\",\"");
 }
 
 USART_SendString(Domain);
 USART_SendString("\",\"");
 USART_SendString(Port);
 USART_SendString("\"\r");

 CRLF_COUNT = 2;
 if(!WaitForExpectedResponse("CONNECT OK"))
 {
  if(Response_Status == SIM900_RESPONSE_TIMEOUT)
  return SIM900_RESPONSE_TIMEOUT;
  return SIM900_RESPONSE_ERROR;
 }
 return SIM900_RESPONSE_FINISHED;
}

uint8_t TCPClient_Send(char* Data)
{
 USART_SendString("AT+CIPSEND\r");
 CRLF_COUNT = -1;
 WaitForExpectedResponse(">");
 USART_SendString(Data);
 USART_SendString("\r\n");
 USART_TxChar(0x1A);

 if(!WaitForExpectedResponse("SEND OK"))
 {
  if(Response_Status == SIM900_RESPONSE_TIMEOUT)
  return SIM900_RESPONSE_TIMEOUT;
  return SIM900_RESPONSE_ERROR;
 }
 return SIM900_RESPONSE_FINISHED;
}

void interrupt ISR()    /* Receive ISR routine */
{
    uint8_t oldstatus = STATUS;
    INTCONbits.GIE = 0;
    char received_char;
    if(RCIF==1){
        RESPONSE_BUFFER[Counter] = RCREG;/* Copy data to buffer & increment counter */
        Counter++;
        if(RCSTAbits.OERR)       /* check if any overrun occur due to continuous reception */
        {           
            CREN = 0;
            NOP();
            CREN = 1;
        }
    }
    INTCONbits.GIE = 1;
    STATUS = oldstatus;
}

intmain()
{
 char _buffer[100];

 #ifdef SEND_DEMO
 uint8_t Sample = 0;
 #endif
 OSCCON = 0x72;   /* Set internal clock to 8MHz */
 USART_Init(9600);  /* Initiate USART with 9600 baud rate */
 INTCONbits.GIE=1;  /* enable Global Interrupt */
 INTCONbits.PEIE=1;  /* enable Peripheral Interrupt */
 PIE1bits.RCIE=1;  /* enable Receive Interrupt */ 

 while(!SIM900_Start());
 TCPClient_Shut();
 TCPClient_ConnectionMode(0); /* 0 = Single; 1 = Multi */
 TCPClient_ApplicationMode(0); /* 0 = Normal Mode; 1 = Transperant Mode */
 AttachGPRS();
 while(!(TCPClient_Connect(APN, USERNAME, PASSWORD)));

 while(1)
 {
  TCPClient_Start(DOMAIN, PORT);

  #ifdef SEND_DEMO
  memset(_buffer, 0, 100);
  sprintf(_buffer, "GET /update?api_key=%s&field1=%d", API_WRITE_KEY, Sample++);
  TCPClient_Send(_buffer);
  MSdelay(600);
  TCPClient_Close();
  MSdelay(15000); /* Thingspeak server delay */
  #endif
  
  #ifdef RECEIVE_DEMO
  memset(_buffer, 0, 100);
  sprintf(_buffer, "GET /channels/%s/feeds/last.txt", CHANNEL_ID);
  TCPClient_Send(_buffer);
  MSdelay(600);
  TCPClient_Close();
  #endif
 }
}

Phản hồi SIM900

Ở cuối ứng dụng, chúng tôi cần kiểm tra phản hồi SIM900. Chúng ta có thể kiểm tra nó trên thiết bị đầu cuối nối tiếp của PC / Laptop. Kết nối SIM900 truyền pin (TX) với pin nhận (RX) của vi điều khiển PIC18F4550 và tới chân nhận (RX) của bộ chuyển đổi usb thành nối tiếp như được minh họa trong hình bên dưới. kết nối usb để chuyển đổi nối tiếp sang PC / Laptop. Mở cổng nối tiếp trên PC / Laptop để xem phản hồi SIM900 cho lệnh AT được gửi từ vi điều khiển PIC.
​​​​​​​Giao diện PIC18F4550 với SIM900 GSM cùng với PC
Giao diện PIC18F4550 với SIM900 GSM cùng với PC 

Bây giờ cho lệnh TCP SEND (được gửi từ vi điều khiển PIC), chúng ta có thể thấy phản hồi dưới đây từ SIM900 trên thiết bị đầu cuối nối tiếp cho máy chủ điều khiển.
​​​​​​​​​​​​​​​​​​​​​Phản hồi TCP SEND

Đáp lại với TCP SEND , chúng tôi nhận được mục nhập dữ liệu không. như trong hình trên, ví dụ 976, 977, v.v.
Đối với các lệnh TCP RECEIVE (được gửi từ Bộ vi điều khiển PIC), chúng ta có thể thấy phản hồi dưới đây từ SIM900 trên thiết bị đầu cuối nối tiếp cho máy chủ điều khiển.
Phản hồi đã nhận của TCP

Để đáp ứng với TCP RECEIVE, chúng tôi nhận được dữ liệu đầu vào cuối cùng cho trường1 trên bảng điều khiển như trong hình trên.
Lưu ý: ở đây chúng tôi đang truy xuất dữ liệu mục nhập cuối cùng trên field1 của máy chủ điều khiển từ điểm do đó chúng tôi nhận được dữ liệu cập nhật mới nhất của trường1 từ máy chủ như được hiển thị trong hình trên, ví dụ "field1": "2" . Trong chương trình, chúng tôi đã sử dụng "GET /channels/119922/feeds/last.txt" để chỉ nhận dữ liệu cập nhật mới nhất.

Cập nhật tại máy chủ thingspeak trên TCP SEND
Đối với TCP SEND, chúng ta có thể thấy đầu ra ở cuối máy chủ. Ở đây chúng tôi đang sử dụng máy chủ thingspeak và gửi số gia tăng tại field1 trên một máy chủ. Chúng tôi nhận được số gia tăng tại field1 của máy chủ thingspeak như thể hiện trong hình dưới đây.
Dữ liệu trên máy chủ Thingspeak


Dữ liệu trên máy chủ Thingspeak


Không có nhận xét nào:

Đăng nhận xét