- Войдите или зарегистрируйтесь, чтобы оставлять комментарии
STM32F4VE LCD ili9341 SIM800L.
Всем привет!
В этой статье хочу рассмотреть подключение GSM модуля SIM800L к отладочной плате STM32F4VE с выводом информации на LCD ili9341. В статье SIM900 я рассказал о двух модулях это SIM900 и SIM800L которые можно использовать в своих проектах для простейших систем домашней автоматизации. В этой статье мы подключим SIM800L зададим первоначальные настройки и прочитаем из него разную информацию с помощью отладочной платы STM32F4VE. Для того чтобы иметь возможность вывести информацию необходимо два основных момента:
1. Подготовленный проект в Keil. Этот проект должен включать в себя работу отладочной платы STM32F4VE с LCD ili9341. Если у вас есть свой проект - вы можете изменить его в ходе этой статьи. Если у вас нет готового проекта, то его необходимо будет создать. Как создать и запустить проект с экраном, мною было рассказано в статьях STM32F4VE LCD ili9341 16bit Keil, а также в продолжении в продолжении статьи STM32F4VE LCD ili9341 16bit Keil INA219. В данной статье я продолжу статью STM32F4VE LCD ili9341 16bit Keil INA219.
2. GSM модуль SIM800L с распаянными контактами для соединения
3. USB - TTL преобразователь для связи с GSM модуль SIM800L с PC.
Подойдет любой из статьи Программаторы FT232RL или CP210X или любой другой в котором вы уверены и он есть в наличии.
Я буду использовать FT232RL
4. Программа терминал. Можно использовать PuTTY, CoolTerm или любую другую удобную для вас программу. Я буду использовать CoolTerm.
5. Блок питания с выходным напряжением 3.8 -4.0 В и током до 2 А. Про ток указано в документации на SIM800L и пренебрегать этим не стоит.
Я буду использовать блок от одного из прототипов своих проектов. Это по сути удобно подключенный аккумулятор с возможностью подзарядки. ИПБ. Ручная работа.
6. Сим карта оператора связи. Это не обязательно. Но тогда не будет возможности получить название оператора.... Я буду использовать оператора связи - полосатого Б.
7. Провода для соединения. По проводам - у меня для подобных соединений есть параллельно соединенные провода. Это удобно когда необходимо знать, какая информация, например отправляется в SIM800L и соответственно параллельно в PC. Я в курсе, что использовать так USART не правильно.. не используйте... спорить не буду.
Если все есть в наличии .. продолжим...
По подключению ...
Очень хорошо все прописано в документе под названием SIM800HL_Hardware_Design_V2.01.pdf
Главное не выходить за рамки разрешенных напряжений!!!
Как сделано у меня .. По входу питания (аккумулятор не должен был быть основным источником) конденсатор 3300 мкф х 10в + конденсатор 0.1 мкф он под конденсатором
По RX и TX для чтения и соответственно записи - у меня на
TX от SIM800L к RX микроконтроллера идет через резистор 1k ....
TX микроконтроллера к RX SIM800L к идет через делитель из резисторов ....
Это сделано для того, чтобы не превышать параметры напряжений указанных в документации!!!!
Еще есть подключенный транзистор к RST - это реализация сброса SIM800L если вдруг перестала работать как необходимо .. в данной статье это не используется ..
Собираем и получается
Как видно на фото мы будем используем - UART 2 у которого
USART2 TX - PA2
USART2 RX - PA3
Вот они см. ниже на схеме отладочной платы STM32F4VE
Итак ... все подключили, программа пока в микроконтроллер не записана ....
Прежде чем начнем дополнять программу в Keil, необходимо убедиться, что SIM800L работает !! для этого -
подключаем USB - TTL преобразователь к PC (преобразователь подключен и к PC и к отладочной плате) и определяем порт по которому будем общаться.
Открываем
Смотрим
Запоминаем номер порта и запускаем программу CoolTerm или любую другую ...Я буду работать с CoolTerm.
Нажимаем Options
Устанавливаем номер порта который запомнили до этого
Перемещаемся во вкладку и устанавливаем Terminal Mode как на фото ниже.
Нажимаем OK и выходим в основное окно программы
Далее смотрим, что как работает светодиод на SIM800L
Вот так работает светодиод когда установлена SIM карта и поиск сети прошел и микросхема на связи и готовая общаться
Если все также как на видео, то начинаем пробовать определить на какой скорости общаться для этого посылаем в SIM800L команду AT в строке
Вполне возможно, что SIM800L ответит сразу т.к. в ней может быть установлен режим автоопределения скорости передачи см. документацию
в моем случае не повезло мне пришлось перебирать ... SIM800L ответила только на скорости 57600, что мною и было установлено в программе CoolTerm при посылке команды AT - ответ от SIM800L - OK
SIM800L ответила и это замечательно ..
Я рекомендую не использовать автоматический скоростной режим если он установлен по умолчанию и рекомендую установить фиксированный. У меня он установлен, но установим его еще раз. Для этого в командной строке программы CoolTerm пишем AT+IPR=57600 (как у меня - можете задать какую пожелаете из возможных). Поделаем это
Вводим и нажимаем ENTER
В ответ модуль ответит OK
Перенастраиваем CoolTerm на заданный фиксированный порт и убеждаемся, что мы на верном пути отправляем команду AT+GMM - идентификатор модуля
В ответ получаем
Все отлично!!
Нажмем кнопку View Hex и увидим
Обратите внимание на то как общается модуль
После каждой команды идут наборы символов OD и OA - пока просто запомните ...
Отлично!!
В итоге модуль
1. Работает
2. настроен на фиксированную скорость передачи данных и мы знаем на какую именно.
3. Модуль готов с нами общаться.
Что сделаем еще ?
Перейдем к программной части и отладочной плате STM32F4VE.
Загружаем проект из статьи STM32F4VE LCD ili9341 16bit Keil INA219 и отключаем инициализацию INA 219 (пока она нам не нужна)!!!!!
Для удобства читаемости программы я перенес файлы с инициализацией портов микроконтроллера в отдельную папку под название Port_ini а также создал папки SIM800L и USART. Названия соответствуют - все что связано с SIM800L делам в файлах папки SIM800L все, что связано с общением с портами USART в папке USART соответственно. Также создал папку Delay и вынес в нее все подпрограммы задержек которые были раньше в файле port_ini.c.
Теперь .. для того чтобы начать читать информацию непосредственно STM32F407VE нужно настроить USART. Это понятно .. настроим. Как поймем, что SIM800L ответила? Да проще простого .. самый удобный механизм у stm32 - прерывание по приходу символа в буфер USARTa. Получается
1. Отправили.
2. Сработало прерывание по наличию в буфере приемном данных
3. Считали буфер в строку и передали в основную программу готовую строчку.
Возможно алгоритм не совершенный .. но вполне рабочий. на нем и остановимся ..
Настроим USART и его прерывания.
У меня настройки USART находятся в файле port_ini.c вместе с настройками портов и светодиодов. Настраиваем
// Конфигурируем USART2
void USART2_Configuration(void)
{
// USART2 у которого:
// USART2 TX - PA2
// USART2 RX - PA3
GPIO_InitTypeDef GPIO_InitStructure; // Создаем структуру порта
USART_InitTypeDef USART_InitStructure; // Создаем структуру USART2
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); //Включаем тактирование порта A
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); //Включаем тактирование порта USART2
// Можно сделать одной строчкой работает и так и так
// RCC_APB1PeriphClockCmd(RCC_AHB1Periph_GPIOA | RCC_APB1Periph_USART2,ENABLE);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource3, GPIO_AF_USART2); //Подключаем PA3 к TX USART2
GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_USART2); //Подключаем PA2 к RX USART2
//Конфигурируем PA2 как альтернативную функцию -> TX UART2.
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//Конфигурируем PA3 как альтернативную функцию -> RX UART.
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// Конфигурируем настройки USART2
USART_InitStructure.USART_BaudRate = 57600; //Скорость обмена 57600 бод
USART_InitStructure.USART_WordLength = USART_WordLength_8b; //Длина слова 8 бит
USART_InitStructure.USART_StopBits = USART_StopBits_1; //1 стоп-бит
USART_InitStructure.USART_Parity = USART_Parity_No ; //Без проверки четности
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //Без аппаратного контроля
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //Включен передатчик и приемник USART2
// Можно задать настройки по умолчанию строкой
// USART_StructInit(&USART_InitStructure);
USART_Init(USART2, &USART_InitStructure); // Инициализируем структуру
// Включаем прерывания и запускаем USART
NVIC_EnableIRQ(USART2_IRQn);
USART_ITConfig(USART2,USART_IT_RXNE,ENABLE);
USART_Cmd(USART2, ENABLE); //Включаем UART
}
теперь напишем функцию отправки информации в USART. У меня она находится в файле serial.с
Основная функция это
void uart_print_string(USART_TypeDef * USARTx, char * string, char newline)
//********************************************************************************************
void uart_send_char (USART_TypeDef * USARTx, char dat)
{
while (!(USARTx->SR & USART_SR_TXE)) {}
USART_SendData(USARTx,dat);
}
void uart_print_string(USART_TypeDef * USARTx, char * string, char newline)
{
while (*string != 0x00){ uart_send_char(USARTx, *string++);}
if (newline!=0){uart_send_char(USARTx, 13);}
}
//*********************************************************************************************
Не трудно догадаться, что строка отправляется в буфер отправки символами
Попробуем протестировать отправку
в main.c в основном цикле добавляем строчку для проверки модуля
Добавляем задержку
Delay_ms(400);
И проверяем программу
Так как у нас параллельно SIM 800L висит USB -USART переходник мы все должны увидеть в терминальной программе. См. видео.
Если по каким-то причинам мы видим в терминальной программе аброказябру или не понятные символы - то скорее всего не правильно срабатывает настройка скорости порта в микроконтроллере.....
Может это быть связано с тем, что не правильно считывается частота работы. Если вы используете мои настройки от предыдущей статьи то возможно стоит убедиться в правильно установки частоты входящего кварцевого резонатора. Для этого в основном окне Keil открываем файл stm32f4xx.h
Ищем строчку HSE_VALUE и устанавливаем ее как на фото ниже.
Если в ней установлено 25000000 это и есть причина не правильного расчета частоты.
Итак мы вывели в терминал команду AT+GMM и получили ответ от модуля. Но пока только в терминальной программе. Чтобы увидеть это на LCD ILI9341 делаем следующее
Пишем обработчик прерывания по приходу символа в буфер приема
void USART2_IRQHandler()
{
char uart_data;
if (USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)//if (USART2->SR & USART_SR_RXNE) // Проверяем, пришл ли что-нибудь в UART
{
uart_data= USART_ReceiveData(USART2);
if (st== 1){
if ( v ==0) {
if(uart_data=='\r' ) //Если пришло сообщение о нажатии Enter...
{
replace_str(&uart_data);
v =1;
}
else
{
uart2_rx_buf[uart2_rx_bit]=uart_data; //Помещаем принятый байт в буфер.
uart2_rx_bit++; //Наращиваем счётчик байтов буфера.
}
}
if (v ==1) {
if(uart_data=='\r' ) //Если пришло сообщение о нажатии Enter...
{
replace_str(&uart_data);
v =2;
}
else
{
uart2_rx_buf[uart2_rx_bit]=uart_data; //USART2->DR; //Помещаем принятый байт в буфер.
uart2_rx_bit++; //Наращиваем счётчик байтов буфера.
}
}
if ( v ==2) {
if(uart_data=='\n' ) //Если пришло сообщение о нажатии Enter...
{
replace_str(&uart_data);
v =3;
}
else
{
uart2_rx_buf[uart2_rx_bit]=uart_data; //USART2->DR; //Помещаем принятый байт в буфер.
uart2_rx_bit++; //Наращиваем счётчик байтов буфера.
}
}
if ( v ==3) {
if(uart_data=='\r' ) //Если пришло сообщение о нажатии Enter...
{
replace_str(&uart_data);
v =4;
}
else
{
uart2_rx_buf[uart2_rx_bit]=uart_data; //USART2->DR; //Помещаем принятый байт в буфер.
uart2_rx_bit++; //Наращиваем счётчик байтов буфера.
}
}
if ( v ==4) {
if(uart_data=='\n' ) //Если пришло сообщение о нажатии Enter...
{
uart2_rx_buf[uart2_rx_bit]=uart_data;
uart2_rx_bit=0; //Сбрасываем счетчик
replace_str(&uart_data);
GPIO_ResetBits(GPIOA, GPIO_Pin_6); //Подаем «0» на P
v =0;
st = 0;
}
else
{
uart2_rx_buf[uart2_rx_bit]=uart_data; //USART2->DR; //Помещаем принятый байт в буфер.
uart2_rx_bit++; //Наращиваем счётчик байтов буфера.
}
}
} //st ==1
//***********************************************************************
if (st== 2){
if (v ==0)
{
if(uart_data=='\r' ) //Если пришло сообщение о нажатии Enter...
{
replace_str(&uart_data);
v =1;
}
else
{
uart2_rx_buf[uart2_rx_bit]=uart_data; //Помещаем принятый байт в буфер.
uart2_rx_bit++; //Наращиваем счётчик байтов буфера.
}
}
if (v ==1)
{
if(uart_data=='\n' ) //Если пришло сообщение о нажатии Enter...
{
replace_str(&uart_data);
v =2;
}
else
{
uart2_rx_buf[uart2_rx_bit]=uart_data; //Помещаем принятый байт в буфер.
uart2_rx_bit++; //Наращиваем счётчик байтов буфера.
}
}
if (v ==2)
{
if(uart_data=='\r' ) //Если пришло сообщение о нажатии Enter...
{
replace_str(&uart_data);
v =3;
}
else
{
uart2_rx_buf[uart2_rx_bit]=uart_data; //Помещаем принятый байт в буфер.
uart2_rx_bit++; //Наращиваем счётчик байтов буфера.
}
}
if (v ==3)
{
if(uart_data=='\n' ) //Если пришло сообщение о нажатии Enter...
{
replace_str(&uart_data);
v =4;
}
else
{
uart2_rx_buf[uart2_rx_bit]=uart_data; //Помещаем принятый байт в буфер.
uart2_rx_bit++; //Наращиваем счётчик байтов буфера.
}
}
if (v ==4)
{
if(uart_data=='\r' ) //Если пришло сообщение о нажатии Enter...
{
replace_str(&uart_data);
v =5;
}
else
{
uart2_rx_buf[uart2_rx_bit]=uart_data; //Помещаем принятый байт в буфер.
uart2_rx_bit++; //Наращиваем счётчик байтов буфера.
}
}
if ( v ==5) {
if(uart_data=='\n' ) //Если пришло сообщение о нажатии Enter...
{
uart2_rx_buf[uart2_rx_bit]=uart_data;
uart2_rx_bit=0; //Сбрасываем счетчик
replace_str(&uart_data);
GPIO_ResetBits(GPIOA, GPIO_Pin_6); //Подаем «0» на P
v =0;
st = 0;
}
else
{
uart2_rx_buf[uart2_rx_bit]=uart_data; //USART2->DR; //Помещаем принятый байт в буфер.
uart2_rx_bit++; //Наращиваем счётчик байтов буфера.
}
}
} ///st== 2
//************************************************************************
if (st== 3){
if (v ==0)
{
if(uart_data=='\r' ) //Если пришло сообщение о нажатии Enter...
{
replace_str(&uart_data);
v =1;
}
else
{
uart2_rx_buf[uart2_rx_bit]=uart_data; //Помещаем принятый байт в буфер.
uart2_rx_bit++; //Наращиваем счётчик байтов буфера.
}
}
if (v ==1)
{
if(uart_data=='\n' ) //Если пришло сообщение о нажатии Enter...
{
replace_str(&uart_data);
v =2;
}
else
{
uart2_rx_buf[uart2_rx_bit]=uart_data; //Помещаем принятый байт в буфер.
uart2_rx_bit++; //Наращиваем счётчик байтов буфера.
}
}
if (v ==2)
{
if(uart_data=='\r' ) //Если пришло сообщение о нажатии Enter...
{
replace_str(&uart_data);
v =3;
}
else
{
uart2_rx_buf[uart2_rx_bit]=uart_data; //Помещаем принятый байт в буфер.
uart2_rx_bit++; //Наращиваем счётчик байтов буфера.
}
}
if ( v ==3) {
if(uart_data=='\n' ) //Если пришло сообщение о нажатии Enter...
{
uart2_rx_buf[uart2_rx_bit]=uart_data;
uart2_rx_bit=0; //Сбрасываем счетчик
replace_str(&uart_data);
GPIO_ResetBits(GPIOA, GPIO_Pin_6); //Подаем «0» на P
v =0;
st = 0;
}
else
{
uart2_rx_buf[uart2_rx_bit]=uart_data; //USART2->DR; //Помещаем принятый байт в буфер.
uart2_rx_bit++; //Наращиваем счётчик байтов буфера.
}
}
} ///st== 3
//**************************************************************
if (st== 4){
if ( v ==0) {
if(uart_data=='\r' ) //Если пришло сообщение о нажатии Enter...
{
replace_str(&uart_data);
v =1;
}
else
{
uart2_rx_buf[uart2_rx_bit]=uart_data; //Помещаем принятый байт в буфер.
uart2_rx_bit++; //Наращиваем счётчик байтов буфера.
}
}
if ( v ==1) {
if(uart_data=='\n' ) //Если пришло сообщение о нажатии Enter...
{
uart2_rx_buf[uart2_rx_bit]=uart_data;
uart2_rx_bit=0; //Сбрасываем счетчик
replace_str(&uart_data);
GPIO_ResetBits(GPIOA, GPIO_Pin_6); //Подаем «0» на P
v =0;
st = 0;
}
else
{
uart2_rx_buf[uart2_rx_bit]=uart_data; //USART2->DR; //Помещаем принятый байт в буфер.
uart2_rx_bit++; //Наращиваем счётчик байтов буфера.
}
}
} //st ==4
//**********************************************************
}
}
//****************************************************************************************
КАКОЙ БОЛЬШОЙ ОБРАБОТЧИК!!!
Скажут (или еще напишут многие), но это только кажется, что он большой ... поясню
Помните
Так вот ... что бы точно принять то, что мы хотим - выше написанный алгоритм позволяет нам сделать достаточно точно для каждого запроса. Как это работает
st ==1, 2...n строчка которая говорит какой ответ и по какому алгоритму принять.
т.е. мы посылаем команду AT-GMM см. на фото выше говорим обработчику , что обрабатывать нужно данные по условию st=N (или 2 или 3 как напишем и определим). Срабатывая по приходу символа в буфер подпрограмма обработки прерывания бегает только по указанному условию например для st =4 и строка начинает формироваться не по завершению строки 0D0A , а тогда когда нужно нам.
//**************************************************************
if (st== 4){
if ( v ==0) {
if(uart_data=='\r' ) //Если пришло сообщение о нажатии Enter...
{
replace_str(&uart_data);
v =1;
}
else
{
uart2_rx_buf[uart2_rx_bit]=uart_data; //Помещаем принятый байт в буфер.
uart2_rx_bit++; //Наращиваем счётчик байтов буфера.
}
}
if ( v ==1) {
if(uart_data=='\n' ) //Если пришло сообщение о нажатии Enter...
{
uart2_rx_buf[uart2_rx_bit]=uart_data;
uart2_rx_bit=0; //Сбрасываем счетчик
replace_str(&uart_data);
GPIO_ResetBits(GPIOA, GPIO_Pin_6); //Подаем «0» на P
v =0;
st = 0;
}
else
{
uart2_rx_buf[uart2_rx_bit]=uart_data; //USART2->DR; //Помещаем принятый байт в буфер.
uart2_rx_bit++; //Наращиваем счётчик байтов буфера.
}
}
} //st ==4
//**********************************************************
Чтобы не получить несколько строчек т.к. 0D и 0A это окончание строки мы заменяем символы на пробелы в функции
//***Замена символов \r и \n на пробелы ************************************
void replace_str(char *s_ss)
{
if(!s_ss) return;
for(;*s_ss; s_ss++)
{
if(*s_ss == '\n' || *s_ss == '\r') *s_ss = ' ';
}
}
// *************************************************************************
И как результат на выходе из прерывания готовая строчка для вывода на LCD
Дополним файл main.c следующим содержанием
st = 3;
uart_print_string(USART2, "AT+GMM\n", 0); // информация о модуле
delay_ms(10);
memset(&str4[0], 0, sizeof(str4));
sprintf(str4,"%s",uart2_rx_buf);
memset(&uart2_rx_buf[0], 0, sizeof(uart2_rx_buf));
lcdSetCursor(10, 45); // xy
lcdPrintf(str4);
delay_ms(2000);
st = 2;
uart_print_string(USART2, "AT+GMR\n", 0); // идентификатор модуля.
delay_ms(10);
memset(&str1[0], 0, sizeof(str1));
sprintf(str1,"%s",uart2_rx_buf);
memset(&uart2_rx_buf[0], 0, sizeof(uart2_rx_buf));
lcdSetCursor(10, 65); // xy
lcdPrintf(str1);
delay_ms(2000);
st = 3;
uart_print_string(USART2, "AT+COPS?\n", 0); // Оператор связи
delay_ms(10);
memset(&str2[0], 0, sizeof(str2));
sprintf(str2,"%s",uart2_rx_buf);
memset(&uart2_rx_buf[0], 0, sizeof(uart2_rx_buf));
lcdSetCursor(10, 85); // xy
lcdPrintf(str2);
delay_ms(2000);
st = 1;
uart_print_string(USART2, "AT+CCLK?", 1); // Дата и время в модуле
delay_ms(10);
memset(&str3[0], 0, sizeof(str3));
sprintf(str3,"%s",uart2_rx_buf);
memset(&uart2_rx_buf[0], 0, sizeof(uart2_rx_buf));
lcdSetCursor(10, 105); // xy
lcdPrintf(str3);
delay_ms(2000);
st = 2;
uart_print_string(USART2, "AT+CBC\n", 0);
delay_ms(10);
memset(&str6[0], 0, sizeof(str6));
sprintf(str6,"%s",uart2_rx_buf);
memset(&uart2_rx_buf[0], 0, sizeof(uart2_rx_buf));
delay_ms(100);
lcdSetCursor(10, 125); // xy
lcdPrintf(str6);
delay_ms(2000);
// включаем светодиоды установленные на плате для понимания что программа работает
GPIO_ResetBits(GPIOA, GPIO_Pin_7); //Подаем «0» на PA
delay_ms(100);
GPIO_SetBits(GPIOA, GPIO_Pin_7); //Подаем «1» на PA
GPIO_SetBits(GPIOA, GPIO_Pin_6); //Подаем «1» на PA
delay_ms(100);
}
}
Результат мы увидим
1. В терминальной программе каждые 2 сек будет опрос модуля и возврат результата
2. На экране LCD
Ура!! У нас все получилось!!!
Конечно, приведенный пример это только образец для понимания, хотя и рабочий и не напрашивается на программу года ...
Для проверки своей платы STM32F4VE LCD ili9341 и модуля SIM800L можно воспользоваться готовым файлом прошивки который создан на основании этой статьи - ссылка
Если есть вопросы или необходим исходник проекта из статьи - пишите по адресу stm32@stm32res.ru или Website feedback