Тестовый пуск GSM модуля SIM800L


• О проекте
• Обратная связь
• Полезные ссылки
• Полезные программы
• Друзья сайта


Последние комментарии

Алексей: Загрузчик для AVR микроконтроллеров
Так он же родной....

Алексей: Загрузчик для AVR микроконтроллеров
Загрузил с увелич...




           

Библиотека для AVR





AXLIB Генератор





Помощь сайту


   
				

Тестовый пуск GSM модуля SIM800L

	
	
	

Дата: 6 Октября 2016. Автор: Алексей

	
	
Всем привет! Давненько мы с вами не говорили про GSM. И так, начнем. Глубокоуважаемые Китайцы забацали новый бюджетный модуль под названием SIM800L. Да, да, этот модуль выпускает ихняяя же фирма SIMCOM. Я по началу боялся его тестить, мол на просторах России его нет и нет гарантии что данный модуль снюхается с нашими сетями. Заниматься перепрошивкой от другого модуля я не хотел, но мне просто чудесно повезло убить двух тараканов одним тапком. Я совсем забыл о замечательном магазине ЧипРезистор который с радостью мне предоставил данный модуль на растерзание.
Вот как выглядит это чудо.

ЫШЬ800Д

Не густо, на плате установлен сам модуль, держатель для микросим, тантал, пару керамики, резистор и светодиод. Как ни странно Китайцы позиционируют данный модуль как шилд для Ардуины. Ардуина вроде как питается от 5 вольт и чаще всего от USB, а если меня не подводит память, то СИМкомовские модули кушают от 3,6в до 4,2 и при этом в пике хотят 2А. Ну да ладно, подключаю к отладочной плате и... Китайцы!!! Все что угодно лишь бы удешевить. Не работает данный модуль от 5 вольт. Моя память меня не подвела. Короче можно долго рассуждать чем его запитать, но я вам покажу один прекрасный девайс, который легко решит эту проблему. Прикупить его можно там же где и SIM800L, а именно в ЧипРезисторе. Модуль представляет собой понижающий импульсник до 3А.


Долее берем этот модуль и припаиваем входные и выходные провода. Заем подключаем к тостеру и настраиваем на 4 вольта.


Далее собираем все в кучу. Ммм, а как!?

Вот схемка, вид сверху.


Мой хаос выглядит вот так.


Проверяем на короткое, вставляем симку, подключаем USB-RS232 и питание. Если ничего не задымилось и замигал светодиод на модуле, значит все в порядке. Далее запускаем како-нибудь терминал, у меня PuTTYn и кидаем первую команду AT. В ответ если получили OK значит все работает.


Бинго! Далее кидаем AT+COPS? и если в ответ получили своего оператора, то для закрепления позвоните себе набрав команду ATD89161234567;. Точка с запятой обязательно! Если модуль дозвонился, то значит он работает с нашими сетями. Я тестил на пчелайне. Если я сейчас скажу что на этом все, то меня закидают яйцами и помидорами, а этого не хочу))) Значит давайте соберем из этого что-нибудь полезное. Например сигнализацию. Прикрутим модуль к МК и будем следить за состояние пару ножек. Как только на ножке появится изменения, то тут же пошлем SMS с оповещением об данном изменении. В роли МК будет выступать ATmegs32a. На ноги PB2 и PB3 прикрутим кнопки. Кнопки имеют общий GND, а для подтяжки используем встроенные резисторы. Для работы с модулем напишем пару функций, а именно инициализации и передачи SMS. Чтож, поехали.

Для начала сконфигурим проект при помощи генератора кода axlib. Для этого выберем МК ATmega32, внешний кварц на 7372800 (такой кварц нужен для уменьшения ошибок при передаче по UART). Настроим UART на скорость 9600. Далее сгенерив проект откроем его в AtmelStudio 6. Первым делом создадим файл sim800l.h в корне проекта и подключим его.

#include <avr/io.h>

#include "main_init.h"
#include "axlib/usart.h"
#include "sim800l.h"

Теперь переходим в наш созданный файл и впишем туда нужные нам дефайны.

// Первая команда, овет OK
#define SIM800L_AT_AT			"AT"				
// Команда на ввод номера абонента для отправки ему SMS сообщения
#define SIM800L_AT_SMS			"AT+CMGS=\""	
// Настройка формата покета		
#define SIM800L_AT_SMS_SET		"AT+CMGF=1"			

Такс, дефайны для упрощения записали, теперь пишем сложную функцию инициализации.

void sim800l_init(void)
{	
	usart_str_rn(SIM800L_AT_AT);
}

Вся сложность данной функции заключается в том, что мы просто передаем команду АТ модулю. С этой команды должен начинать работать модуль. Следующая функция немного посложнее.

BYTE sim800l_send_sms(BYTE *num, BYTE *text, BYTE lenght)
{
	// Массив для получения ответов от модуля
	BYTE str[20] = {0};
		
	_delay_ms(1000);
	
	// Настройка режима передачи
	usart_str_rn(SIM800L_AT_SMS_SET);	
	
	// Подача номера телефона абонента
	usart_str_out(SIM800L_AT_SMS, 9);
	usart_str_out(num, 12);
	usart_str_rn("\"");
	
	// Ожидание начала ввода текста	
	_delay_ms(3000);
	
	// Отправка текста 
	usart_str_out(text, lenght);
	str[0] = 0x1A;
	str[1] = 0;
	usart_str_rn(str);
	
	// Ждем OK
	usart_str_in(str, 18);
	if(!((str[14] == 0x4F) & (str[15] == 0x4B))) return 0x34;
	
	return 0x30;
}

Вот тут я понял всю сущность дешевизны данного модуля. Эта фиговина напрочь отказывалась стабильно возвращать ответы. Как я только не извращался, и ставил таймауты по приходу данных гигантские, и задержки лепил. Короче плюнул на те ответы что плавали во времени и натыкал задержек. Для работы это не сильно мешает. Платим за дешевизну. Поехали по функции. Первым делом тыкаем настройку передачи пакета. Это нужно чтобы модуль отправлял данные получив номер телефона, а затем ожидал принятия текста. Затем передаем номер телефона абонента которому отправляем SMS. Берем его из аргумента данной функции. Есть одно но! Номер телефона должен иметь формат вида: +79161234567. +7 обязательно, этот модуль в отличии от 900-тых не понимает 8. После передачи номера абонента просто тупим 3 секунды. Все это время модуль не спеша пережевывает номер и по хрен знает какому алгоритму, как раз на этих задержках я подорвался, выдает нам приглашение на ввод текста значком > 3 секунд железно хватает пережевать и выплюнуть приглашение. После 3 секунд кидаем текст сообщения. Его так же берем из аргумента данной функции и от туда же длину текста для функций UART. Ведь мы не знаем сколько буковок вы собираетесь послать. Если внимательно присмотреться, то можно заметить байт 0x1A в конце текста сообщения. Это команда Ctrl+Z нужна для окончания передачи текста. Когда модуль получит эту команду, то все бросит и передаст SMS. Все, с данным файлом закончили, переходим в основной файл программы.

#define BUTTON_1	"Nazhata knopka 1"
#define BUTTON_2	"Nazhata knopka 2"

// Инициализация GSM модуля
sim800l_init();
	
// Настройка портов ввода вывода на чтение
DDRB = 0x00;

// Включаем подтяжку внутренним резистором
PORTB |= (1 << PB2) | (1 << PB3);

	while(1)
	{
		// Если нажали кнопку 1
		if(!(PINB & (1 << PB2)))
		{
			// Ждем пока не отпустили кнопку
			while(!(PINB & (1 << PB2)));
			sim800l_send_sms("+79161234567", BUTTON_1, 16);
		}
		
		// Если нажали кнопку 2
		if(!(PINB & (1 << PB3)))
		{
			// Ждем пока не отпустили кнопку
			while(!(PINB & (1 << PB3)));
			sim800l_send_sms("+79161234567", BUTTON_2, 16);
		}
		
	}

Что мы тут видим. Два дефайна с заранее подготовленным текстом. Затем мы инициализируем модуль. Затем настраиваем ножки 2 и 3 порта В на вход и подтягиваем внутренний резистор к плюсу питания. Затем в бесконечном цикле проверяем на нажатие кнопок. Как только какая-либо из кнопок будет нажата, сразу вваливаемся в бесконечный цикл и ждем пока не отпустят кнопку. После того как кнопку отпустили вызываем функцию отправки SMS с заранее продефаненым текстом. Вот и все.))) Проект выкладывать не буду так как его можно сгенерить axlib генератором и скопипастить текст отсюда. Ой, да, вот что я получил на телефон.))





Фыва    09.10.16 23:29

Если верить mt-system, то 800 серия это приемник 900 серии, которую якобы сворачивают к концу 2016 года. Поэтому довольно странно читать о таких досадных косяках как зажатые ответы.
может чего в датишах нового завелось? Или ты чисто по аналогии с 900 кидал команды, особо не раскуривая?

Алексей    09.10.16 23:39

Меня эти паузы насторожили еще когда я с ней общался через терминал. Думал порт тормозит, но на ноуте та же песня.

Юрий    05.03.17 20:36

Подскажите как заставить модуль, по запросу USSD отправлять баланс,считывать и устанавливать на ножках Avrки уровнь. В общем хочется сделать "Умный дом" Спасибо

Алексей    06.03.17 12:36

Я на эту тему уже писал статью. Вот она.

Олег    28.03.17 02:43

Разъясните пожалуйста. Для чего в функции usart_str_rn
передаётся \n ,для работы с симмодулем это нужно или на всякий случай?
Что делает символ /" тут

#define SIM800L_AT_SMS "AT+CMGS=\""

и

usart_str_out(SIM800L_AT_SMS, 9);
usart_str_out(num, 12);
usart_str_rn("\"");

тут тоже /" /r /n
почему нельзя разом usart_str_rn(AT+CMGS="+7xxxxxxxxxx") , как в терминале ?
И

usart_str_out(text, lenght);
str[0] = 0x1A;понятно
str[1] = 0; зачем ноль?
usart_str_rn(str); и ещё /r /n ?

Алексей    28.03.17 12:33

--> Что делает символ /" тут
Символ \ ставится перед служебными символами для того чтобы эти символы превратить в простые. Дело в том что двойная кавычка это служебный символ. Его используют чтобы передать строку в массив. А для того чтобы компилятор прочитал именно как символ, то перед служебными символами ставят обратную косую черту.
Пример:



BYTE data[] = "Какой-то текст \"Текст в кавычках\"";


Теперь внутренние кавычки запишутся в массив как символы.

--> почему нельзя разом usart_str_rn(AT+CMGS="+7xxxxxxxxxx") , как в терминале ?

Потому что функция принимает в качестве аргумента указатель на первый элемент массива с номером абонента. Если написать сразу, то SMS будут высылаться вечно только этому абоненту. И изменить можно будет лишь переписав код.

--> Разъясните пожалуйста. Для чего в функции usart_str_rn
передаётся \n

Потому что документация на модуль SIMCOM требует в конце команды вводить код конца строки и перевода каретки.

Олег    28.03.17 14:05

Спасибо, Алексей это осознал, имею проблему с передачей 1А, в таблице служебных символов нет комбинации с \... .

Алексей    28.03.17 15:04

А как должен выглядеть символ Ctrl+z? Или например пробел, табуляция. Поэтому передается именно кодом. Например \r\n можно записать как два байта 0x0D, 0x0A. Это одно и тоже.

Олег    28.03.17 16:59

Это я понял , коммада отправилась вот так


str[0] = 0x4D;
str[1] = 0x4B;
str[2] = 0x4D;// три буквы текст для теста.
str[3] = 0x1A;
str[4] = 0;
usart_str_rn(str);

, текст наверно могу строкой , но 1А получается только через массив, как-то проще нельзя?

Алексей    28.03.17 17:14



void usart_char_out(BYTE data)

Просто посылает один байт в порт.

Евгений    07.05.17 17:47

BYTE sim800l_send_sms(BYTE *num, BYTE *text, BYTE lenght)
{
// Массив для получения ответов от модуля
BYTE str[10] = {0};
далее исходник
// Ждем OK
usart_str_in(str, 18);
if(!((str[14] == 0x4F) & (str[15] == 0x4B))) return 0x34;
Откуда взялись 14 и 15 индекс в массиве, если он объявлен явно str[10] ?

Алексей    07.05.17 20:05

А вот такой я валенок. Массив не на 10 ячеек, а на 20)))

Евгений    08.05.17 20:13

Бывает )) Так и понял что опечатка. Начал свой код писать, взял за основу и просто сразу увидел

Алексей    08.05.17 21:34

Советую лучше использовать SIM800C вместо L. Те же деньги но у C есть синезуб в модуле.

Евгений    12.05.17 06:43

Да, у меня как раз 800C модули. Алексей, после выполнения чтения, в str пусто, в чем может быть проблема ? Команды на модуль уходят и модуль отвечает (проверено лог.анализатором), но в str пусто
// Ждем OK
usart_str_in(str, 18);
if(!((str[14] ==

Евгений    12.05.17 18:57

Алексей. Разобрался в чем проблема, в функции usart_str_in было принятие 18 байт, а модуль отвечал только 9тью байтами, соответственно функция воспринимала данный ответ как таймаут. (BYTE usart_str_in(BYTE *str, BYTE count)
{
BYTE out = 0;
BYTE data = 0;
BYTE timeout = 0;

while(count > data) // здесь пока 18>9 - таймаут
{
data = GetData();

// Если в течении 250 мс данные не пришли
// то выйти из функции и вернуть 0
if(timeout >= 250)
{
ClearBuffer();
return out;
}

timeout++;
_delay_ms(1);
}

out = OutBufferStr(str, count);
return out;
}
)
А как быть если не известно какой длины придет ответ?

Алексей    12.05.17 20:03

Опрашивать буфер на прием больше одного байта, а потом подождав вычитать весь пакет из буфера.

Евгений    12.05.17 20:21

Алексей, не совсем понял идею, поясни плз

Алексей    12.05.17 20:58




main()
{

// Количество принятых байт в буфер
BYTE len_pocket = 0;

// Массив для данных
BYTE data[40] = {0};

while(1)
{
// Смотрим что в буфере
len_pocket = usart_data();

// Проверяем пришло ли что в буфер
if(len_pocket > 0)
{
// Если пришло, ждем
// расчет паузы (1000/(битрейт/10))*макс байт.
// Пример битрейт 19200, макс байт 40. (1000/1920)*40 = 20.8мс

// Пауза для гарантированного получения всех байт
_delay_ms(22);

// Получаем количество принятых байт
len_pocket = usart_data();

// Записываем данные в массив
usart_str_in(data, len_pocket);

// Теперь в массиве data лежат все принятые байты.
}
}
}


Евгений    12.05.17 21:25

Алексей, спасибо, идею понял наглядно, буду пробовать. Еще хотел спросить про два слейва и мастер, по поводу потери связи при сдергивании линии, не пробовал макетировать ?

Алексей    12.05.17 22:18

Пока нет. Очень много работы. Я вообще из-за нее подзабил на сайт.




Чтобы вставить ссылку используйте форму вида[url]http://www.адрес.ru[/url][text]текст ссылки[/text]
Чтобы вставить код используйте форму вида[code]код[/code]

Имя:   





  








Вверх


Рейтинг@Mail.ru Яндекс.Метрика