Skip to content

Repository files navigation

SimpleSensor

Набор функций, реализующих базовый функционал датчика пламени.

Этот проект предназначен для обучения базовым принципам разработки пожарных и охранных датчиков.

Работает на базе отладочных плат NUCLEO-L053R8 и NUCLEO-F072RB с подключенным модулем KY-026.

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

Flame

Далее будет пошагово описано как сгенерировать проект в STM32CubeMX и добавить в него весь необходимый функционал.

Сборка пустого проекта в STM32CubeMX

Необходимо создать новый проект на базе отладочной платы NUCLEO-L053R8 или NUCLEO-F072RB.

Запускаем программу STM32CubeMX.

STM32CubeMX является визуальным графическим редактором для конфигурирования микроконтроллеров семейства STM32, позволяющим генерировать код на основе языка Си.

https://www.st.com/en/development-tools/stm32cubemx.html

Для создания проекта выбираем File→New Project, или воспользуемся горячей клавишей Ctr+N.

Выбираем Board Selector. В строке Commercial Part Number (находится в левой части окна раздела Board Selector) вводим название отладочной платы — NUCLEO-L053R8 или NUCLEO-F072RB. Из списка Boadrs List (располагается в центре окна) выбираем соотвествующую отладочную плату и нажимаем кнопку Start Project. Откроется окно Board Project Options. Нажимаем кнопку Yes (инициализируем всю периферию по умолчанию).

Для USART2 (вкладка Connectivity) в NVIC Settings включаем USART2 global interrupt. На вкладке Advanced Settings в разделе Driver Selector\USART выбираем «LL». Это означает подключение низкоуровневых библиотек для работы с последовательным портом.

На вкладке Clock Configuration для платы NUCLEO-L053R8 выбираем источник тактирования HSI в System Clock Mux. Для платы NUCLEO-F072RB он выбран по умолчанию.

На вкладке Pinout&Configuration для выводов контроллера PC0 и PC1 выбираем режимы работы и наименования:

  • PC0 режим GPIO mode выбираем Output Open Drain, имя User Label указываем OUT_OD.
  • PC1 режим GPIO mode выбираем External Interrupt Mode with Rising edge trigger detection, имя User Label указываем IN_RISING.

Включаем прерывание для соотвествующих ножек контроллера. Во вкладке NVIC Interrupt Table для GPIO включаем EXTI line 0 and 1 interrupts.

Для сторожевого таймера IWDG выбираем Activated.

Указываем наименование и путь к файлам проекта. Генерируем код кнопкой GENERATE CODE.

Сборка готового проекта

Открываем ранее созданный проект.

Файлы cmd.h, fifo.h, log.h, time.h, usart.h копируем в \Core\Inc.

Файлы cmd.c, fifo.c, log.c, time.c, usart.c копируем в \Core\Src.

Корректировка main.h

В файл main.h добавляем следующий код:

extern volatile uint8_t alarm_sensor;

Корректировка main.c

В main.c добавляем все заголовки:

#include "cmd.h"
#include "log.h"
#include "fifo.h"
#include "time.h"
#include "usart.h"

Добавляем определения:

#define IWDG_ENABLE

Добавляем переменные:

volatile uint8_t alarm_sensor;

В функцию MX_USART2_UART_Init() добавляем вызов USART_Init().

Добавляем следующие функции:

Простое преобразование из числа в строку

#define MAX_NUMBER_LEN 11
unsigned char * itoa(int32_t value, unsigned char base){
static volatile unsigned char res[MAX_NUMBER_LEN+1] = {0};
static unsigned char str[MAX_NUMBER_LEN] = {0};
unsigned char resnum = 0;
if (value<0)
{
res[resnum++] = '-';
value=-value;
}else
if (value==0)
{
res[0]='0';
res[1]=0;
return (unsigned char*)res;
}
unsigned char ctr = MAX_NUMBER_LEN-1;
str[ctr] = 0;
while ((value != 0) && (ctr-1)){
str[--ctr] = "0123456789abcdef"[value % base];
value /= base;
}
while (ctr<MAX_NUMBER_LEN-1)
res[resnum++]=str[ctr++];
res[resnum] = 0;
return (unsigned char*)res;
}

Вычитывание состояний из лога и отправка их в последованиельный порт

void ReadAndShowStates()
{
for (int i=0;i<MAX_EVENTS;i++)
{
EVENT e = Read_Event();
if (!e.time) continue;
//Write state to terminal
USART_Write_String((unsigned char*)"time=");
USART_Write_String(itoa(e.time,10));
USART_Write_String((unsigned char*)", event=");
switch (e.data)
{
case CMD_LED_ON:
USART_Write_String((unsigned char*)"LED ON");
break;
case CMD_LED_OFF:
USART_Write_String((unsigned char*)"LED OFF");
break;
case CMD_OUT_ON:
USART_Write_String((unsigned char*)"OUT ON");
break;
case CMD_OUT_OFF:
USART_Write_String((unsigned char*)"OUT OFF");
break;
case CMD_BUTTON:
USART_Write_String((unsigned char*)"BUTTON PRESSED");
break;
case CMD_ALARM:
USART_Write_String((unsigned char*)"ALARM");
break;
case CMD_INFINITY:
USART_Write_String((unsigned char*)"INFINITY CYCLE");
break;
default:
USART_Write_String(itoa(e.data,10));
}
USART_Write_String((unsigned char*)"\r\n");
USART_Send();
HAL_Delay(10);
#ifdef IWDG_ENABLE
HAL_IWDG_Refresh(&hiwdg);
#endif
}
}

В функцию main() добавляем следующий код:

#ifdef IWDG_ENABLE
MX_IWDG_Init();
#endif
alarm_sensor = 0;
LL_USART_EnableIT_RXNE(USART2); USART_Write_String((unsigned char*)"Ready\r\n");

В тело цикла while добавляем следующий код:

if (HAL_GPIO_ReadPin(B1_GPIO_Port, B1_Pin)==GPIO_PIN_RESET)
{
USART_Write_String((unsigned char*)"Button pressed\r\n");
Write_Event(CMD_BUTTON);
USART_Send();
HAL_Delay(100);
}
if (alarm_sensor)
{
USART_Write_String((unsigned char*)"Alarm!!!\r\n");
Write_Event(CMD_ALARM);
USART_Send();
alarm_sensor = 0;
HAL_Delay(100);
}
uint16_t cmd = Cmd_Read();
if (cmd != CMD_NA)
{
USART_Write_String((unsigned char*)"cmd=");
USART_Write_String(itoa(cmd,10));
USART_Write_String((unsigned char*)"\r\n");
if (cmd!=CMD_READ_LOG)
Write_Event(cmd);
char OK = 1;
switch (cmd)
{
case CMD_EEPROM_TEST:
USART_Write_String((unsigned char*)"Start EEPROM test\r\n");
USART_Send();
HAL_StatusTypeDef status = HAL_OK;
for (uint32_t adr = 0;adr<MAX_EVENTS;adr++)
{
status = Write_EEPROM(adr*4, (adr+10)<<16);
#ifdef IWDG_ENABLE
HAL_IWDG_Refresh(&hiwdg);
#endif
if (status!=HAL_OK) break;
}
uint32_t err = 0;
if (status==HAL_OK){
for (uint32_t adr = 0;adr<MAX_EVENTS;adr++)
{
if (Read_EEPROM(adr*4)!=((adr+10)<<16))
{
err = 1;
break;
}
}
}
OK = (status==HAL_OK)&&(!err);
break;
case	CMD_LED_ON:
HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_SET);
break;
case	CMD_LED_OFF:
HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_RESET);
break;
case	CMD_OUT_ON:
HAL_GPIO_WritePin(OUT_OD_GPIO_Port, OUT_OD_Pin, GPIO_PIN_RESET);
break;
case	CMD_OUT_OFF:
HAL_GPIO_WritePin(OUT_OD_GPIO_Port, OUT_OD_Pin, GPIO_PIN_SET);
break;
case	CMD_READ_LOG:
ReadAndShowStates();
break;
case	CMD_BUTTON:
break;
case	CMD_ALARM:
alarm_sensor = 1;
break;
case	CMD_INFINITY:
while (1) {};
break;
default:
OK = 0;
}
if (OK)
{
USART_Write_String((unsigned char*)"OK\r\n");
}else
USART_Write_String((unsigned char*)"FAILED\r\n");
}
USART_Send();
HAL_Delay(10);
#ifdef IWDG_ENABLE
HAL_IWDG_Refresh(&hiwdg);
#endif

Корректировка stm32f0xx_it.с

В файл stm32f0xx_it.с добавляем следующий код:

#include "time.h"
#include "usart.h"

В функцию SysTick_Handler добавляем вызов TimeShift1ms().

В функцию USART2_IRQHandler() добавляем вызов USART_IRQ().

В EXTI0_1_IRQHandler добавляем код:

alarm_sensor = 1;

Проверка

Компилируем код и запускаем на отладочной плате. Для взаимодействия с отладочной платой можно использовать программу ComTest.

https://github.com/exatb/ComTest

Должна быть корректная реакция на все команды.

image

Далее подключаем модуль KY-026 как показано на рисунке

Nucleo and KY-026

При возникновении пламени в зоне видимости фотодиода должно появляться сообщение Alarm!

Для ленивых

Собранные проекты для плат:

About

Набор функций, реализующих базовый функционал датчика пламени. Предназначен для обучения базовым принципам разработки пожарных и охранных датчиков.

Resources

Stars

4 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages