Министерство науки и высшего образования Российской Федерации
Федеральное государственное автономное образовательное учреждение высшего образования
ТОМСКИЙ ГОСУДАРСТВЕННЫЙ УНИВЕРСИТЕТ СИСТЕМ УПРАВЛЕНИЯ И РАДИОЭЛЕКТРОННИКИ (ТУСУР)
Кафедра комплексной информационной безопасности электронно-вычислительных систем (КИБЭВС)
ВНЕШНИЕ ИНТЕРФЕЙСЫ МИКРОКОНТРОЛЛЕРА
Отчет по лабораторной работе №7
по дисциплине «Основы программирования микроконтроллеров»
Вариант №4
Студенты гр. 712-2: ___________ Л.С. Болтушкин
___________ Н.А. Рыбин
___________ Д.В. Шабанова __________
Руководитель Старший преподаватель кафедры КИБЭВС
_______ __________ Д.С. Беляков
__________
Томск 2025
Введение
Целью данной лабораторной работы является углубленное изучение архитектуры ARM на примере микроконтроллера STM32F103RBT6, изучение межпроцессного взаимодействия в OCPB FreeRTOS и интерфейсов микроконтроллера.
Вариант №4 – Скорость работы UART - 115200. Один поток считывает раз в 200 мс значение температуры или давления и отправляет его через очередь во второй поток. Второй поток выводит данные значения с их единицами измерения в консоль. Тип значения меняется одинарным нажатием на кнопку.
1 Ход работы
Для выполнения данной лабораторной работы были использованы файлы, созданные в предыдущей лабораторной работе.
Рисунок 1.1 – Использованные файлы
Выполнена инициализация интерфейса UART (USART2) для организации обмена данными с ПК через виртуальный COM-порт. В соответствии с вариантом 4, скорость передачи была установлена на 11520 бод. Были настроены выводы PA2 и PA3, после чего реализована и интегрирована в проект функция для отправки текстовых сообщений в терминал.
После этого осуществлена полная инициализация датчика BME280: установлены режимы измерения, коэффициенты усреднения и фильтрации. Реализованы функции чтения калибровочных коэффициентов и получения измеренных значений температуры, влажности и давления с применением алгоритмов компенсации.
В соответствии с заданием варианта 4 была разработана многопоточная программа на базе существующего проекта FreeRTOS, включающая два потока.
После был создан файл «main.c», результат выполнения кода представлен на рисунке 1.2.
Код программы представлен в приложении А.
Рисунок 1.2 – Результат выполнения программы
Заключение
В ходе выполнения лабораторной работы были углубленно изучены архитектура микроконтроллера STM32F103RBT6 и основы работы с внешними интерфейсами UART и SPI в среде ОСРВ FreeRTOS. Были получены практические навыки настройки и использования данных интерфейсов, а также организации межзадачного взаимодействия с помощью очередей сообщений.
Приложение а
(обязательное)
Листинг кода файла «main.c»
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "stm32f1xx.h"
#include <stdint.h>
/* ==================== КОНСТАНТЫ ==================== */
#define SYSTEM_CLOCK 8000000
#define UART_BAUD_RATE 115200
#define LED_PIN 5 // PA5
#define BUTTON_PIN 13 // PC13
/* BME280 registers */
#define BME280_ID_REG 0xD0
#define BME280_CTRL_HUM 0xF2
#define BME280_CTRL_MEAS 0xF4
#define BME280_CONFIG 0xF5
#define BME280_TEMP_MSB 0xFA
#define BME280_PRESS_MSB 0xF7
/* ==================== RTOS ==================== */
typedef struct {
uint8_t type; // 0-temp, 1-pressure
int32_t value;
} sensor_data_t;
QueueHandle_t sensor_queue;
/* ==================== BME280 CALIB ==================== */
static uint16_t dig_T1;
static int16_t dig_T2, dig_T3;
static uint16_t dig_P1;
static int16_t dig_P2, dig_P3, dig_P4, dig_P5, dig_P6, dig_P7, dig_P8, dig_P9;
static int32_t t_fine;
/* ==================== GLOBAL ==================== */
volatile uint8_t measure_mode = 0; // 0-temp, 1-pressure
/* ==================== UART ==================== */
static void init_uart(void) {
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
RCC->APB1ENR |= RCC_APB1ENR_USART2EN;
GPIOA->CRL &= ~(GPIO_CRL_MODE2 | GPIO_CRL_CNF2);
GPIOA->CRL |= GPIO_CRL_MODE2 | GPIO_CRL_CNF2_1;
GPIOA->CRL &= ~(GPIO_CRL_MODE3 | GPIO_CRL_CNF3);
GPIOA->CRL |= GPIO_CRL_CNF3_0;
GPIOA->ODR |= (1 << 3);
USART2->BRR = SYSTEM_CLOCK / UART_BAUD_RATE;
USART2->CR1 |= USART_CR1_TE | USART_CR1_UE;
}
static void uart_send_char(char c) {
while (!(USART2->SR & USART_SR_TXE));
USART2->DR = c;
}
static void uart_send_string(const char *s) {
while (*s) uart_send_char(*s++);
}
/* ==================== SPI ==================== */
static void init_spi(void) {
RCC->APB2ENR |= RCC_APB2ENR_IOPBEN | RCC_APB2ENR_AFIOEN;
RCC->APB1ENR |= RCC_APB1ENR_SPI2EN;
GPIOB->CRH &= ~(GPIO_CRH_MODE13 | GPIO_CRH_CNF13);
GPIOB->CRH |= GPIO_CRH_MODE13 | GPIO_CRH_CNF13_1;
GPIOB->CRH &= ~(GPIO_CRH_MODE14 | GPIO_CRH_CNF14);
GPIOB->CRH |= GPIO_CRH_CNF14_0;
GPIOB->CRH &= ~(GPIO_CRH_MODE15 | GPIO_CRH_CNF15);
GPIOB->CRH |= GPIO_CRH_MODE15 | GPIO_CRH_CNF15_1;
GPIOB->CRL &= ~(GPIO_CRL_MODE1 | GPIO_CRL_CNF1);
GPIOB->CRL |= GPIO_CRL_MODE1;
GPIOB->BSRR = (1 << 1);
SPI2->CR1 = SPI_CR1_MSTR | SPI_CR1_BR_1 |
SPI_CR1_SSM | SPI_CR1_SSI | SPI_CR1_SPE;
}
static uint8_t spi_transfer(uint8_t d) {
while (!(SPI2->SR & SPI_SR_TXE));
SPI2->DR = d;
while (!(SPI2->SR & SPI_SR_RXNE));
return SPI2->DR;
}
static void spi_read(uint8_t reg, uint8_t *buf, uint8_t len) {
GPIOB->BRR = (1 << 1);
spi_transfer(reg | 0x80);
for (uint8_t i = 0; i < len; i++) buf[i] = spi_transfer(0);
GPIOB->BSRR = (1 << 1);
}
static void spi_write(uint8_t reg, uint8_t val) {
GPIOB->BRR = (1 << 1);
spi_transfer(reg & 0x7F);
spi_transfer(val);
GPIOB->BSRR = (1 << 1);
}
/* ==================== BME280 ==================== */
static void bme280_calibrate(void) {
uint8_t d[24];
spi_read(0x88, d, 6);
dig_T1 = (d[1]<<8)|d[0];
dig_T2 = (d[3]<<8)|d[2];
dig_T3 = (d[5]<<8)|d[4];
spi_read(0x8E, d, 18);
dig_P1 = (d[1]<<8)|d[0];
dig_P2 = (d[3]<<8)|d[2];
dig_P3 = (d[5]<<8)|d[4];
dig_P4 = (d[7]<<8)|d[6];
dig_P5 = (d[9]<<8)|d[8];
dig_P6 = (d[11]<<8)|d[10];
dig_P7 = (d[13]<<8)|d[12];
dig_P8 = (d[15]<<8)|d[14];
dig_P9 = (d[17]<<8)|d[16];
}
static void bme280_init(void) {
uint8_t id;
spi_read(BME280_ID_REG, &id, 1);
spi_write(BME280_CTRL_HUM, 0x01);
spi_write(BME280_CTRL_MEAS, 0x27);
spi_write(BME280_CONFIG, 0xA0);
bme280_calibrate();
}
static int32_t bme280_get_temperature(void) {
uint8_t d[3];
spi_read(BME280_TEMP_MSB, d, 3);
int32_t adc = (d[0]<<12)|(d[1]<<4)|(d[2]>>4);
int32_t v1 = ((((adc>>3)-(dig_T1<<1)))*dig_T2)>>11;
int32_t v2 = (((((adc>>4)-dig_T1)*((adc>>4)-dig_T1))>>12)*dig_T3)>>14;
t_fine = v1+v2;
return (t_fine*5+128)>>8; // *100
}
static uint32_t bme280_get_pressure(void) {
uint8_t d[3];
spi_read(BME280_PRESS_MSB, d, 3);
int32_t adc = (d[0]<<12)|(d[1]<<4)|(d[2]>>4);
int64_t v1 = ((int64_t)t_fine)-128000;
int64_t v2 = v1*v1*(int64_t)dig_P6;
v2 += ((v1*(int64_t)dig_P5)<<17);
v2 += (((int64_t)dig_P4)<<35);
v1 = ((v1*v1*(int64_t)dig_P3)>>8)+((v1*(int64_t)dig_P2)<<12);
v1 = (((((int64_t)1)<<47)+v1)*dig_P1)>>33;
if (!v1) return 0;
int64_t p = 1048576-adc;
p = (((p<<31)-v2)*3125)/v1;
return (uint32_t)(p>>8)/100;
}
/* ==================== BUTTON ==================== */
static void init_button(void) {
RCC->APB2ENR |= RCC_APB2ENR_IOPCEN;
GPIOC->CRH &= ~(GPIO_CRH_MODE13 | GPIO_CRH_CNF13);
GPIOC->CRH |= GPIO_CRH_CNF13_1;
GPIOC->ODR |= (1 << 13);
}
static void init_exti(void) {
RCC->APB2ENR |= RCC_APB2ENR_AFIOEN;
AFIO->EXTICR[3] |= AFIO_EXTICR4_EXTI13_PC;
EXTI->IMR |= EXTI_IMR_MR13;
EXTI->FTSR |= EXTI_FTSR_TR13;
NVIC_EnableIRQ(EXTI15_10_IRQn);
}
void EXTI15_10_IRQHandler(void) {
if (EXTI->PR & EXTI_PR_PR13) {
EXTI->PR = EXTI_PR_PR13;
measure_mode ^= 1;
}
}
/* ==================== TASKS ==================== */
static void sensor_task(void *arg) {
sensor_data_t d;
while (1) {
d.type = measure_mode;
d.value = (measure_mode == 0)
? bme280_get_temperature()
: bme280_get_pressure();
xQueueSend(sensor_queue, &d, portMAX_DELAY);
vTaskDelay(pdMS_TO_TICKS(200));
}
}
static void print_number(int32_t n) {
char b[10]; int i=0;
if (n==0) { uart_send_char('0'); return; }
if (n<0){ uart_send_char('-'); n=-n; }
while(n){ b[i++]=n%10+'0'; n/=10; }
while(i--) uart_send_char(b[i]);
}
static void processor_task(void *arg) {
sensor_data_t d;
while (1) {
if (xQueueReceive(sensor_queue, &d, portMAX_DELAY)) {
if (d.type == 0) {
uart_send_string("Temperature: ");
print_number(d.value/100);
uart_send_char('.');
print_number(d.value%100);
uart_send_string(" C\r\n");
} else {
uart_send_string("Pressure: ");
print_number(d.value);
uart_send_string(" hPa\r\n");
}
}
}
}
/* ==================== MAIN ==================== */
int main(void) {
init_uart();
init_spi();
init_button();
init_exti();
bme280_init();
sensor_queue = xQueueCreate(5, sizeof(sensor_data_t));
xTaskCreate(sensor_task, "Sensor", 256, NULL, 2, NULL);
xTaskCreate(processor_task, "Print", 256, NULL, 1, NULL);
vTaskStartScheduler();
while (1);
}
