Урок 52
Часть 4
Датчик давления LPS25HB
В предыдущей части занятия мы написали функцию считывания и предварительной обработки значения давления, также изменили код функции фильтра скользящего среднего.
Также мы отобразили значение температуры и давления (причём сразу в трёх единицах измерения в терминальной программе).
Давайте также добавим возможность отключать фильтр скользящего среднего кнопкой. Добавим переменную
void Press_Get_Press (float* pData)
{
uint8_t btnstat;
И добавим опрос кнопки и применим фильтр
for(i = 0; i < 3; i++) raw_data |= (((uint32_t)buffer[i]) << (8 * i));
btnstat=HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13);
//Если кнопка не нажата,
//то вызовем фильтр скользящего среднего
if(btnstat!=0) raw_data = MovingAverage(raw_data);
*pData = ( float )raw_data / 4096.0f;
То же самое проделаем и для температуры. Только если использовать ту же функцию фильтра скользящего среднего, не избежать артефактов, так как вызываться она будет для температуры и для давления по очереди, а работаем мы с глобальными переменными, которые хранят предыдущие показания. Данные показания непременно попутаются и ничего у нас не выйдет, даже если мы будем использовать локальные переменные. Поэтому после долгих танцев с бубном (структуры, входные значения и тд) было принято решение занести глобальные переменные, кроме счётчика в функцию фильтра, затем данную функцию скопировать и добавить ещё раз. Затем добавить ещё один счётчик специально для температуры, изменить имя добавленной функции, не может же у нас быть двух функций с одинаковым именем, добавить инициализацию счётчика для буфера под температуру и затем уже применить вторую функцию в низкоуровневой функции снятия показаний температуры.
А теперь по порядку.
Удалим глобальные переменные, добавим счётчик для температуры
//счётчик наполнения буферов скользящего среднего
volatile int8_t avg_cnt;
volatile int8_t avg_cnt_temp;
Добавим локальные переменные в функцию
//———————————————
int32_t MovingAverage(int32_t dt)
{
//буфер для скользящего среднего
static int32_t buf_avg[8]={0};
//сумма для среднего арифметического
static int64_t tmp64; int32_t dt_ret=0;
if(avg_cnt<8)
Скопируем и исправим функцию фильтра
//———————————————
int32_t MovingAverageTemp(int32_t dt)
{
//буфер для скользящего среднего
static int32_t buf_avg[8]={0};
//сумма для среднего арифметического
static int64_t tmp64; int32_t dt_ret=0;
if(avg_cnt_temp<8)
{
buf_avg[avg_cnt_temp]=dt;
if(avg_cnt_temp==7)
{
tmp64=buf_avg[7]+buf_avg[6]+buf_avg[5]+buf_avg[4]+
buf_avg[3]+buf_avg[2]+buf_avg[1]+buf_avg[0];
dt_ret=tmp64/8;
}
avg_cnt_temp++;
}
else
{
//вычтем из общей суммы первый (самые старый) элемент
tmp64-=buf_avg[0];
//сдвинем буфер на 1 элемент
memcpy((void*)buf_avg,(void*)(buf_avg+1),sizeof(int32_t)*7);
//заменим 7 элемент на новый
buf_avg[7]=dt;
//прибавим новый элемент
tmp64+=dt;
//обновим среднее значение
dt_ret=tmp64/8;
}
return dt_ret;
}
//———————————————
Вызовем функцию фильтра в функции чтения температуры
void Press_Get_Temp (float* pData)
{
uint8_t btnstat;
int16_t raw_data=0,tmp_data=0;
buffer[0]=Press_IO_Read(LPS25HB_ADDRESS,LPS25HB_TEMP_OUT_L_REG);
buffer[1]=Press_IO_Read(LPS25HB_ADDRESS,LPS25HB_TEMP_OUT_H_REG);
raw_data = (((uint16_t)buffer[1]) << 8) + (uint16_t)buffer[0];
btnstat=HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13);
//Если кнопка не нажата,
//то вызовем фильтр скользящего среднего
if(btnstat!=0) raw_data = MovingAverageTemp(raw_data);
tmp_data = raw_data / 48 + 425;
*pData = ( float )tmp_data / 10.0f;
}
Ну и инициализация
//инициализируем счетчики заполнения скользящего среднего
avg_cnt=0;
avg_cnt_temp=0;
HAL_Delay(1000);
Теперь мы попытаемся посмотреть результат без кнопки и с кнопкой, но уже в программе визуализации, которую я опять, как всегда, доработал (ну ни могу я без доработок). Доработка заключена в том, что мы теперь напрямую получаем значение с плавающей точкой, доработал диапазоны под плавающую точку, а также было включено ещё поле редактирования для установки сдвига значения. Ну и самое главное, что мы теперь не тупо смотрим на клеточки, а появилась шкала, которая уже конкретно говорит о показаниях по y. Правда показания пока только для двух значений, и одновременно при большом разбеге их значений мы их не увидим, но в дальнейшем я планирую ещё доработать и для второго значения добавлю свою шкалу справа от графика, а также добавлю для второго значения отдельный делитель и отдельный сдвиг. Но пока и так уже вроде как круто.
Но прежде чем мы посмотрим результат, мы должны будем немного доработать код, чтобы как-то отправить значения с плавающей точкой в программу визуализации. Для этого, во-первых, закомментируем вызов функции обработки и отправки данных в файле main.c в бесконечном цикле и раскомментируем в обработчике таймера
/* USER CODE BEGIN 3 */
//Press_Read();
}
if(huart2.RxXferCount==0)
{
Press_Read();
HAL_UART_Receive_IT(&huart2,(uint8_t*)str,8);
Теперь закомментируем в функции обработки и отправки данных код для отправки в текстовом виде, раскомментируем код для отправки в бинарном виде, закомментируем задержку, преобразуем наши показания датчиков из значения с плавающей точкой в обычный бинарный вид в памяти, а также исправим отправку в USART. Отправлять мы теперь будем 10 восьмиразрядных величин
//sprintf(str1,»TEMP:%06f; PRESS:%06f mbar; %06f atm; %06f mm Hgrn», temper, press, patm, pmmhg);
//HAL_UART_Transmit(&huart2, (uint8_t*)str1,strlen(str1),0x1000);
uint8_t *t = (uint8_t *)&temper;
uint8_t *p = (uint8_t *)&press;
buf2[0]=0x11;
buf2[1]=0x55;
buf2[2]=(uint8_t)(*(uint32_t*)t);
buf2[3]=(uint8_t)((*(uint32_t*)t)>>8);
buf2[4]=(uint8_t)((*(uint32_t*)t)>>16);
buf2[5]=(uint8_t)((*(uint32_t*)t)>>24);
buf2[6]=(uint8_t)(*(uint32_t*)p);
buf2[7]=(uint8_t)((*(uint32_t*)p)>>8);
buf2[8]=(uint8_t)((*(uint32_t*)p)>>16);
buf2[9]=(uint8_t)((*(uint32_t*)p)>>24);
HAL_UART_Transmit(&huart2,buf2,10,0x1000);
//HAL_Delay(200);
}
Скомпилируем код, прошьём контроллер и посмотрим результат с кнопкой и без кнопки в программе визуализации, также применяя различные значения пределов и сдвига показаний (нажмите на картинку для увеличения размера)
Измеряя температуру, подносим палец руки к датчику постепенно и также постепенно его убираем, сначала без кнопки потом с кнопкой. Небольшая разница, но всё-таки есть.
Теперь давление. Тут без изменений, так как повлиять на атмосферное давление тяжело, разве только отладочную плату засунуть в шину автомобильную и накачать (шутка). Также попробуем без кнопки и с кнопкой, применив другие значения делителя и сдвига в программе визуализации (нажмите на картинку для увеличения размера)
Здесь уже конечно разница очевидна. Первые и последние пять клеточек – это с фильтром скользящего среднего, а средние пять клеточек – это без фильтра. Так что применение фильтра даёт свои результаты.
Предыдущая часть Программирование МК STM32 Следующий урок
Техническая документация на датчик:
Программа NS Port Monitor для значений с плавающей точкой
Отладочную плату можно приобрести здесь Nucleo STM32F401RE
Оценочную плату можно приобрести здесь STM32 X-NUCLEO-IKS01A1
Смотреть ВИДЕОУРОК
Добавить комментарий