add external temperature sensor support, allow to cycle through different test modes

This commit is contained in:
dymik739 2025-02-19 19:05:47 +02:00
parent 2bcf89efe1
commit 47733fdae4
8 changed files with 315 additions and 130 deletions

11
Core/Inc/external_temp.h Normal file
View File

@ -0,0 +1,11 @@
#ifndef __EXTERNAL_TEMP
#define __EXTERNAL_TEMP
extern ADC_HandleTypeDef hadc1;
void external_temp_show_celsius(void);
void external_temp_show_fahrenheit(void);
#endif

10
Core/Inc/generic_macros.h Normal file
View File

@ -0,0 +1,10 @@
#ifndef __GENERIC_MACROS
#define __GENERIC_MACROS
#define PANIC(status) \
do { \
GPIOD->ODR = status; \
while (1) {} \
} while (0)
#endif

24
Core/Inc/lcd.h Normal file
View File

@ -0,0 +1,24 @@
#ifndef __LCD
#define __LCD
#define DISPLAY_RS ((uint16_t) (0x1U << 7))
#define DISPLAY_RW ((uint16_t) (0x1U << 10))
#define DISPLAY_ENA ((uint16_t) (0x1U << 11))
#define DISPLAY_POLL_UNTIL_READY do { while (display_read_status() & 0x80) {} } while (0)
#define DISPLAY_SET_INCREMENT do { display_write_instruction_byte(0x06); } while (0)
#define DISPLAY_SET_DECREMENT do { display_write_instruction_byte(0x04); } while (0)
#define DISPLAY_SET_CURSOR(line, position) do { display_write_instruction_byte(0x80 | (line << 6) | position); } while (0)
#define DISPLAY_CLEAR do { display_write_instruction_byte(0x01); } while (0)
void display_init(void);
uint8_t display_read_status(void);
void display_write_instruction_byte(uint8_t code);
void display_write_data_byte(uint8_t code);
void display_write_data_seq(char *codes);
#endif

View File

98
Core/Src/external_temp.c Normal file
View File

@ -0,0 +1,98 @@
#include "main.h"
#include "generic_macros.h"
#include "lcd.h"
#include "external_temp.h"
static uint32_t external_temp_read(void)
{
HAL_ADC_Start(&hadc1);
if (HAL_ADC_PollForConversion(&hadc1, 100) != HAL_OK)
PANIC(0x4000);
return HAL_ADC_GetValue(&hadc1);
}
static int external_temp_convert_to_celsius(uint32_t value)
{
return (2512 - value) << 2;
}
static int external_temp_convert_to_fahrenheit(uint32_t value)
{
return (2953 - value) * 50 / 7;
}
static void external_temp_print(int temperature)
{
int add_sign = temperature < 0;
if (add_sign)
temperature = ~(temperature - 1); // if value is not positive, the string conversion will break
int temp1 = temperature;
for (int i = 0; i < 2; i++) {
temperature /= 10;
display_write_data_byte('0' + (char) (temp1 - temperature * 10));
temp1 = temperature;
}
display_write_data_byte('.');
for (int i = 0; i < 3; i++) {
temperature /= 10;
display_write_data_byte('0' + (char) (temp1 - temperature * 10));
temp1 = temperature;
if (temp1 == 0) {
display_write_data_seq(" ");
break;
}
}
if (add_sign) {
DISPLAY_SET_CURSOR(1, 0);
display_write_data_byte('-');
}
}
static void external_temp_print_celsius(int temperature)
{
DISPLAY_SET_CURSOR(1, 7);
DISPLAY_SET_DECREMENT;
display_write_data_seq("C ");
external_temp_print(temperature);
}
static void external_temp_print_fahrenheit(int temperature)
{
DISPLAY_SET_CURSOR(1, 7);
DISPLAY_SET_DECREMENT;
display_write_data_seq("F ");
external_temp_print(temperature);
}
void external_temp_show_celsius(void)
{
DISPLAY_CLEAR;
DISPLAY_SET_INCREMENT;
display_write_data_seq("Temperature");
uint32_t value = external_temp_read();
int temp = external_temp_convert_to_celsius(value);
external_temp_print_celsius(temp);
}
void external_temp_show_fahrenheit(void)
{
DISPLAY_CLEAR;
DISPLAY_SET_INCREMENT;
display_write_data_seq("Temperature");
uint32_t value = external_temp_read();
int temp = external_temp_convert_to_fahrenheit(value);
external_temp_print_fahrenheit(temp);
}

92
Core/Src/lcd.c Normal file
View File

@ -0,0 +1,92 @@
#include "main.h"
#include "lcd.h"
#include "generic_macros.h"
void display_init(void)
{
// switch to 4-bit 2-line mode
display_write_instruction_byte(0x28);
// clear display
display_write_instruction_byte(0x01);
// enable display
display_write_instruction_byte(0x0C);
// move cursor to first line
display_write_instruction_byte(0x80);
}
uint8_t display_read_status(void)
{
// make sure GPIOE is in correct mode
GPIOE->MODER = 0x00504000;
if (GPIOE->MODER != 0x00504000)
PANIC(0x4000);
uint8_t status = 0;
GPIOE->ODR = 0x0;
GPIOE->BSRR = DISPLAY_RW;
GPIOE->BSRR = DISPLAY_ENA;
status |= (GPIOE->IDR & 0xF000) >> 8;
GPIOE->BSRR = (DISPLAY_ENA << 16);
GPIOE->BSRR = DISPLAY_ENA;
status |= (GPIOE->IDR & 0xF000) >> 12;
GPIOE->BSRR = (DISPLAY_ENA << 16);
GPIOE->ODR = 0x0;
return status;
}
void display_write_instruction_byte(uint8_t code)
{
DISPLAY_POLL_UNTIL_READY;
// make sure GPIOE is in correct mode
GPIOE->MODER = 0x55504000;
if (GPIOE->MODER != 0x55504000)
PANIC(0x4000);
GPIOE->ODR = (code & 0xF0) << 8;
GPIOE->BSRR = DISPLAY_ENA;
GPIOE->BSRR = (DISPLAY_ENA << 16);
GPIOE->ODR = (code & 0x0F) << 12;
GPIOE->BSRR = DISPLAY_ENA;
GPIOE->BSRR = (DISPLAY_ENA << 16);
}
void display_write_data_byte(uint8_t code)
{
DISPLAY_POLL_UNTIL_READY;
// make sure GPIOE is in correct mode
GPIOE->MODER = 0x55504000;
if (GPIOE->MODER != 0x55504000)
PANIC(0x4000);
GPIOE->ODR = ((code & 0xF0) << 8) | (DISPLAY_RS);
GPIOE->BSRR = DISPLAY_ENA;
GPIOE->BSRR = DISPLAY_ENA << 16;
GPIOE->ODR = ((code & 0x0F) << 12) | (DISPLAY_RS);
GPIOE->BSRR = DISPLAY_ENA;
GPIOE->BSRR = DISPLAY_ENA << 16;
}
void display_write_data_seq(char *codes)
{
for (size_t i = 0; i < 16; i++) {
if (codes[i] != 0)
display_write_data_byte(codes[i]);
else
break;
}
}

View File

@ -22,6 +22,10 @@
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "generic_macros.h"
#include "lcd.h"
#include "external_temp.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
@ -32,18 +36,6 @@
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
#define DISPLAY_RS ((uint16_t) (0x1U << 7))
#define DISPLAY_RW ((uint16_t) (0x1U << 10))
#define DISPLAY_ENA ((uint16_t) (0x1U << 11))
#define PANIC(status) \
do { \
GPIOD->ODR = status; \
while (1) {} \
} while (0)
#define POLL_UNTIL_READY do { while (read_status() & 0x80) {} } while (0)
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
@ -52,16 +44,23 @@
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
ADC_HandleTypeDef hadc1;
/* USER CODE BEGIN PV */
int change = 1;
void ((*executors[])(void)) = {
external_temp_show_celsius,
external_temp_show_fahrenheit
};
int current_executor_id = 0;
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_ADC1_Init(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
@ -69,70 +68,6 @@ static void MX_GPIO_Init(void);
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
uint8_t read_status(void)
{
// make sure GPIOE is in correct mode
GPIOE->MODER = 0x00504000;
if (GPIOE->MODER != 0x00504000)
PANIC(0x4000);
uint8_t status = 0;
GPIOE->ODR = 0x0;
GPIOE->BSRR = DISPLAY_RW;
GPIOE->BSRR = DISPLAY_ENA;
status |= (GPIOE->IDR & 0xF000) >> 8;
GPIOE->BSRR = (DISPLAY_ENA << 16);
GPIOE->BSRR = DISPLAY_ENA;
status |= (GPIOE->IDR & 0xF000) >> 12;
GPIOE->BSRR = (DISPLAY_ENA << 16);
GPIOE->ODR = 0x0;
return status;
}
void write_instruction_byte(uint8_t code)
{
POLL_UNTIL_READY;
// make sure GPIOE is in correct mode
GPIOE->MODER = 0x55504000;
if (GPIOE->MODER != 0x55504000)
PANIC(0x4000);
GPIOE->ODR = (code & 0xF0) << 8;
GPIOE->BSRR = DISPLAY_ENA;
GPIOE->BSRR = (DISPLAY_ENA << 16);
GPIOE->ODR = (code & 0x0F) << 12;
GPIOE->BSRR = DISPLAY_ENA;
GPIOE->BSRR = (DISPLAY_ENA << 16);
}
void write_data_byte(uint8_t code)
{
POLL_UNTIL_READY;
// make sure GPIOE is in correct mode
GPIOE->MODER = 0x55504000;
if (GPIOE->MODER != 0x55504000)
PANIC(0x4000);
GPIOE->ODR = ((code & 0xF0) << 8) | (DISPLAY_RS);
GPIOE->BSRR = DISPLAY_ENA;
GPIOE->BSRR = DISPLAY_ENA << 16;
GPIOE->ODR = ((code & 0x0F) << 12) | (DISPLAY_RS);
GPIOE->BSRR = DISPLAY_ENA;
GPIOE->BSRR = DISPLAY_ENA << 16;
}
/* USER CODE END 0 */
/**
@ -164,67 +99,21 @@ int main(void)
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_ADC1_Init();
/* USER CODE BEGIN 2 */
GPIOD->ODR = 0xF000;
// switch to 4-bit 2-line mode
write_instruction_byte(0x28);
// reset display
write_instruction_byte(0x01);
// enable display
write_instruction_byte(0x0C);
// move cursor to first line
write_instruction_byte(0x80);
// write string
char a[] = "Well, hi there!";
for (int i = 0; i < sizeof(a)-1; i++) {
write_data_byte(a[i]);
}
/*
// move cursor to second line
write_instruction_byte(0xC0);
while (read_status() & 0x80) {}
// write another string
char b[] = "I'm doing it!";
for (int i = 0; i < sizeof(b)-1; i++) {
write_data_byte(b[i]);
while (read_status() & 0x80) {}
}
*/
display_init();
GPIOD->ODR = 0x0000;
unsigned int counter = 0;
write_instruction_byte(0x04); // set address decrement after write
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
counter += change;
counter &= 0xFFFF;
unsigned int c = counter;
write_instruction_byte(0xC4);
for (int i = 0; i < 5; i++) {
int current_digit = c % 10;
c /= 10;
write_data_byte('0' + (char) current_digit);
}
HAL_Delay(10);
executors[current_executor_id]();
HAL_Delay(250);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
@ -273,6 +162,58 @@ void SystemClock_Config(void)
}
}
/**
* @brief ADC1 Initialization Function
* @param None
* @retval None
*/
static void MX_ADC1_Init(void)
{
/* USER CODE BEGIN ADC1_Init 0 */
/* USER CODE END ADC1_Init 0 */
ADC_ChannelConfTypeDef sConfig = {0};
/* USER CODE BEGIN ADC1_Init 1 */
/* USER CODE END ADC1_Init 1 */
/** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
*/
hadc1.Instance = ADC1;
hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2;
hadc1.Init.Resolution = ADC_RESOLUTION_12B;
hadc1.Init.ScanConvMode = DISABLE;
hadc1.Init.ContinuousConvMode = DISABLE;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.NbrOfConversion = 1;
hadc1.Init.DMAContinuousRequests = DISABLE;
hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
if (HAL_ADC_Init(&hadc1) != HAL_OK)
{
Error_Handler();
}
/** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
*/
sConfig.Channel = ADC_CHANNEL_9;
sConfig.Rank = 1;
sConfig.SamplingTime = ADC_SAMPLETIME_480CYCLES;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN ADC1_Init 2 */
/* USER CODE END ADC1_Init 2 */
}
/**
* @brief GPIO Initialization Function
* @param None
@ -286,6 +227,7 @@ static void MX_GPIO_Init(void)
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOE_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();

View File

@ -41,7 +41,9 @@
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
extern int change;
extern void ((*executors[])(void));
extern void *current_executor(void);
extern int current_executor_id;
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
@ -205,9 +207,15 @@ void EXTI0_IRQHandler(void)
{
/* USER CODE BEGIN EXTI0_IRQn 0 */
change *= -1;
GPIOD->ODR = 0x1000;
current_executor_id += 1;
current_executor_id &= 1;
for (int i = 900000; i > 0; i--) asm("nop");
GPIOD->ODR = 0x0000;
for (int i = 0; i < 400000; i++) {asm("nop");}
/* USER CODE END EXTI0_IRQn 0 */
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
/* USER CODE BEGIN EXTI0_IRQn 1 */