Урок 52
Часть 3
Датчик давления LPS25HB
В предыдущей части занятия мы написали инициализацию датчика давления, а также написали функцию считывания и предварительной обработки значения температуры.
Функцию Mag_Read также переименуем в Press_Read
//———————————————
void Press_Read(void)
{
Исправим это и в вызовах в main.c: и в обработчике и в бесконечном цикле, а в бесконечном цикле заодно и раскомментируем
/* USER CODE BEGIN 3 */
Press_Read();
//Press_Read();
HAL_UART_Receive_IT(&huart2,(uint8_t*)str,8);
Начнём теперь вносить изменения в данную функцию. Добавим туда новую переменную, лишние переменные и код уберём, закомментируем код отправки в USART для программы визуализации, а раскомментируем и внесём определённые изменения в функцию отправки в USART для терминальной программы, а также прибавим задержку
void Press_Read(void)
{
float temper;
Press_Get_Temp(&temper);
sprintf(str1,»TEMP:%06frn», temper);
HAL_UART_Transmit(&huart2, (uint8_t*)str1,strlen(str1),0x1000);
/*
buf2[0]=0x11;
buf2[1]=0x55;
buf2[2]=(uint8_t)(val[0]>>8);
buf2[3]=(uint8_t)val[0];
buf2[4]=(uint8_t)(val[1]>>8);
buf2[5]=(uint8_t)val[1];
buf2[6]=(uint8_t)(val[2]>>8);
buf2[7]=(uint8_t)val[2];
HAL_UART_Transmit(&huart2,buf2,8,0×1000);
*/
HAL_Delay(200);
}
Скомпилируем код, прошьём контроллер и посмотрим результат в терминальной программе. В процессе просмотра несколько раз притронемся к датчику пальцем на продолжительное время и увидим изменения температуры
Также нам будет необходима функция считывания показаний давления из датчика.
Скопируем функцию Press_Get_Temp, вставим её ещё раз в код и исправим ей имя
void Press_Get_Press (float* pData)
{
Начнём вносить в неё изменения.
Так как у нас датчик давления 24-битный, то для считывания в нём используются 3 регистра
Поэтому использовать мы будем 3 элемента буфера и 32-битные величины для расчёта, одну переменную удалим, т.к. расчётов будет меньше ввиду отсутствия сдвига
void Press_Get_Press (float* pData)
{
uint8_t i;
int32_t raw_data=0;
buffer[0]=Press_IO_Read(LPS25HB_ADDRESS,LPS25HB_PRESS_OUT_XL_REG);
buffer[1]=Press_IO_Read(LPS25HB_ADDRESS,LPS25HB_PRESS_OUT_L_REG);
buffer[2]=Press_IO_Read(LPS25HB_ADDRESS,LPS25HB_PRESS_OUT_H_REG);
for(i = 0; i < 3; i++) raw_data |= (((uint32_t)buffer[i]) << (8 * i));
*pData = ( float ) raw_data / 4096.0f;
}
Для расчёта мы также пользуемся технической документацией
Добавим некоторый код в высокоуровневую функцию обработки показаний датчика
float temper, press;
Press_Get_Temp(&temper);
Press_Get_Press(&press);
sprintf(str1,»TEMP:%06f; PRESS:%06frn», temper, press);
Соберём код, прошьём МК и посмотрим результат
Теперь попробуем показания давления преобразовать в другие единицы измерения. У нас оно в гектопаскалях или в милибарах, а мы преобразуем его ещё в атмосферы и в миллиметры ртутного столба. Для этого также нужно будет добавить некоторый код, но прежде не забудем добавить ячеек в нашу строковую переменную, а то я забыл и получил массу багов
uint8_t buf2[14]={0};
char str1[100]={0};
А теперь код
float temper, press, patm, pmmhg;
Press_Get_Temp(&temper);
Press_Get_Press(&press);
patm = press/1010;
pmmhg = press/1.333f;
sprintf(str1,»TEMP:%06f; PRESS:%06f mbar; %06f atm; %06f mm Hgrn», temper, press, patm, pmmhg);
Скомпилируем код, прошьём контроллер и посмотрим результат нашей работы
Теперь уберём шум, которого и так почти нет за счёт того, что он уже убран. По температуре его вообще нет, очень хорошо работает внутренний фильтр датчика, а по давлению он незначителен. Ну давайте всё же применим скользящее среднее. Только применять его будет целесообразнее в низкоуровневых функциях, так как уже преобразованное значение в значение с плавающей точкой тяжелее фильтровать и фильтр задействует больше аппаратных ресурсов, что не хотелось бы вовсе. С температурой будет проще, так как величина 16-битная, а вот с давлением нужна будет другая функция из-за того, что используется значение 24-битное. Но мы пойдём другим путём и просто подправим нашу функцию усреднения значений в универсальную, просто сделав её 32-битной.
Для этого, во-первых, исправим входной аргумент, сделаем его не адресом а обычной переменной, но тогда появится и возвращаемое значение
int32_t MovingAverage(int32_t* dt)
Также исправим и глобальные переменные, оси уберём, так как работать будем только с одним значением
//буфер для скользящего среднего
volatile int32_t buf_avg[8]={0};
Данную переменную также сделаем обычной, не массивом
//сумма для среднего арифметичесого
volatile int64_t tmp64;
Добавим переменную в функцию для возврата значения
int32_t MovingAverage(int32_t dt)
{
int32_t dt_ret;
Вот вся функция с исправлениями
//———————————————
int32_t MovingAverage(int32_t dt)
{
int32_t dt_ret=0;
if(avg_cnt<8)
{
buf_avg[avg_cnt]=dt;
if(avg_cnt==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++;
}
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;
}
//———————————————
В следующей части урока мы уже передадим оба показания, причём с плавающей точкой через шину USART на ПК, применим на них фильтр скользящего среднего и увидим изменение показаний в графиках.
Предыдущая часть Программирование МК STM32 Следующая часть
Техническая документация на датчик:
Программа NS Port Monitor для значений с плавающей точкой
Отладочную плату можно приобрести здесь Nucleo STM32F401RE
Оценочную плату можно приобрести здесь STM32 X-NUCLEO-IKS01A1
Смотреть ВИДЕОУРОК
Добавить комментарий