├── VL6180X ├── UKF.png ├── VL6180X.PNG ├── Distribution │ ├── Mean.png │ ├── Std.png │ ├── Distribution.png │ ├── VL6180X_Distribution.m │ └── Unscented_Kalman_Filter.m ├── ReadMe.md └── VL6180X.h ├── ADXL345 ├── ADXL345.jpg └── ReadMe.md ├── Micro SD SPI ├── SPI.png ├── FATFS.png ├── UART.png ├── Sélection_015.png ├── User_diskio.png ├── fatfs_sd.h ├── user_diskio.c └── ReadMe.md ├── FlashMemory ├── memory.png ├── ReadWrite.h ├── ReadMe.md └── ReadWrite.c ├── DS3231 ├── Sélection_041.png ├── DS3231 │ ├── DS3231.h │ └── DS3231.c └── ReadMe.md ├── Encoder ├── Sélection_063.png ├── Sélection_064.png ├── Encoder.h ├── ReadMe.md └── Encoder.c ├── FlashMemory_F4 ├── memory.png ├── ReadWrite.h ├── ReadMe.md └── ReadWrite.c ├── MAX31865 ├── Selección_021.png ├── MAX31865.h ├── ReadMe.md └── MAX31865.c ├── MCP23017 ├── Sélection_025.png ├── ReadMe.md └── MCP23017.h ├── SSD1306 128x32 ├── Sélection_008.png ├── SSD1306.h └── ReadMe.md ├── ILI9341 Touch LCD ├── Sélection_013.png ├── LCDTools │ ├── LCDTools.h │ └── printf.h ├── ReadMe.md └── LCDCore │ └── TSC2046.c ├── LiquidCrystal I2C ├── Selección_017.png ├── Selección_018.png ├── Selección_020.png ├── ReadMe.md └── LiquidCrystal_I2C.h ├── PCA9685 PWM Servo ├── Sélection_016.png ├── ReadMe.md ├── PCA9685.h └── PCA9685.c ├── MCP3008 ├── IC-MCP-3008-5-1-1-800x800.jpg ├── MCP3008.h ├── ReadMe.md └── MCP3008.c ├── nRF24L01 Radio RX-TX ├── Sélection_060.png └── ReadMe.md ├── ADS1015_ADS1115 ├── Adafruit-1085-30091131-02.jpg └── ReadMe.md ├── HX711 Load Cell Amplifier ├── Sélection_018.png ├── ReadMe.md ├── HX711.h └── HX711.c ├── Optimized ILI9341 Touch LCD ├── Touch Screen │ ├── Logics │ │ ├── One_button_logic.c │ │ ├── Two_button_logic.c │ │ ├── Main_logic.c │ │ ├── Numpad_logic.c │ │ └── Keyboard_logic.c │ ├── Frames │ │ ├── Tools │ │ │ ├── Intro_frame.c │ │ │ ├── Keyboard_frame.c │ │ │ ├── Numpad_frame.c │ │ │ └── Plot_frame.c │ │ ├── Measurement_and_time_frame.c │ │ ├── SAE J1939 Frames │ │ │ ├── SAE_J1939_Request_frame.c │ │ │ ├── SAE_J1939_Address_frame.c │ │ │ └── SAE_J1939_DM1_DM2_frame.c │ │ ├── Main_frame.c │ │ ├── Encoder_revolutions_settings_frame.c │ │ ├── Date_time_alarm_settings_frame.c │ │ ├── PWM_frequency_settings_frame.c │ │ └── Analog_input_settings_frame.c │ ├── Dialogs │ │ ├── Information_ok_dialog.c │ │ └── Question_yes_no_dialog.c │ ├── Touch_screen.h │ └── LCD.c └── ReadMe.md ├── FlashMemory_F3 ├── ReadWrite.h ├── ReadMe.md └── ReadWrite.c ├── LICENSE └── MCP4728 ├── mcp4728.h ├── ReadMe.md └── mcp4728.c /VL6180X/UKF.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielMartensson/STM32-Libraries/HEAD/VL6180X/UKF.png -------------------------------------------------------------------------------- /ADXL345/ADXL345.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielMartensson/STM32-Libraries/HEAD/ADXL345/ADXL345.jpg -------------------------------------------------------------------------------- /Micro SD SPI/SPI.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielMartensson/STM32-Libraries/HEAD/Micro SD SPI/SPI.png -------------------------------------------------------------------------------- /VL6180X/VL6180X.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielMartensson/STM32-Libraries/HEAD/VL6180X/VL6180X.PNG -------------------------------------------------------------------------------- /FlashMemory/memory.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielMartensson/STM32-Libraries/HEAD/FlashMemory/memory.png -------------------------------------------------------------------------------- /Micro SD SPI/FATFS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielMartensson/STM32-Libraries/HEAD/Micro SD SPI/FATFS.png -------------------------------------------------------------------------------- /Micro SD SPI/UART.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielMartensson/STM32-Libraries/HEAD/Micro SD SPI/UART.png -------------------------------------------------------------------------------- /DS3231/Sélection_041.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielMartensson/STM32-Libraries/HEAD/DS3231/Sélection_041.png -------------------------------------------------------------------------------- /Encoder/Sélection_063.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielMartensson/STM32-Libraries/HEAD/Encoder/Sélection_063.png -------------------------------------------------------------------------------- /Encoder/Sélection_064.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielMartensson/STM32-Libraries/HEAD/Encoder/Sélection_064.png -------------------------------------------------------------------------------- /FlashMemory_F4/memory.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielMartensson/STM32-Libraries/HEAD/FlashMemory_F4/memory.png -------------------------------------------------------------------------------- /MAX31865/Selección_021.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielMartensson/STM32-Libraries/HEAD/MAX31865/Selección_021.png -------------------------------------------------------------------------------- /MCP23017/Sélection_025.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielMartensson/STM32-Libraries/HEAD/MCP23017/Sélection_025.png -------------------------------------------------------------------------------- /Micro SD SPI/Sélection_015.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielMartensson/STM32-Libraries/HEAD/Micro SD SPI/Sélection_015.png -------------------------------------------------------------------------------- /Micro SD SPI/User_diskio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielMartensson/STM32-Libraries/HEAD/Micro SD SPI/User_diskio.png -------------------------------------------------------------------------------- /VL6180X/Distribution/Mean.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielMartensson/STM32-Libraries/HEAD/VL6180X/Distribution/Mean.png -------------------------------------------------------------------------------- /VL6180X/Distribution/Std.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielMartensson/STM32-Libraries/HEAD/VL6180X/Distribution/Std.png -------------------------------------------------------------------------------- /SSD1306 128x32/Sélection_008.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielMartensson/STM32-Libraries/HEAD/SSD1306 128x32/Sélection_008.png -------------------------------------------------------------------------------- /ILI9341 Touch LCD/Sélection_013.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielMartensson/STM32-Libraries/HEAD/ILI9341 Touch LCD/Sélection_013.png -------------------------------------------------------------------------------- /LiquidCrystal I2C/Selección_017.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielMartensson/STM32-Libraries/HEAD/LiquidCrystal I2C/Selección_017.png -------------------------------------------------------------------------------- /LiquidCrystal I2C/Selección_018.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielMartensson/STM32-Libraries/HEAD/LiquidCrystal I2C/Selección_018.png -------------------------------------------------------------------------------- /LiquidCrystal I2C/Selección_020.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielMartensson/STM32-Libraries/HEAD/LiquidCrystal I2C/Selección_020.png -------------------------------------------------------------------------------- /PCA9685 PWM Servo/Sélection_016.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielMartensson/STM32-Libraries/HEAD/PCA9685 PWM Servo/Sélection_016.png -------------------------------------------------------------------------------- /MCP3008/IC-MCP-3008-5-1-1-800x800.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielMartensson/STM32-Libraries/HEAD/MCP3008/IC-MCP-3008-5-1-1-800x800.jpg -------------------------------------------------------------------------------- /VL6180X/Distribution/Distribution.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielMartensson/STM32-Libraries/HEAD/VL6180X/Distribution/Distribution.png -------------------------------------------------------------------------------- /nRF24L01 Radio RX-TX/Sélection_060.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielMartensson/STM32-Libraries/HEAD/nRF24L01 Radio RX-TX/Sélection_060.png -------------------------------------------------------------------------------- /ADS1015_ADS1115/Adafruit-1085-30091131-02.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielMartensson/STM32-Libraries/HEAD/ADS1015_ADS1115/Adafruit-1085-30091131-02.jpg -------------------------------------------------------------------------------- /HX711 Load Cell Amplifier/Sélection_018.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielMartensson/STM32-Libraries/HEAD/HX711 Load Cell Amplifier/Sélection_018.png -------------------------------------------------------------------------------- /MCP3008/MCP3008.h: -------------------------------------------------------------------------------- 1 | /* 2 | * MCP3008.h 3 | * 4 | * Created on: 14 Feb 2020 5 | * Author: root 6 | */ 7 | 8 | #ifndef MCP3008_MCP3008_H_ 9 | #define MCP3008_MCP3008_H_ 10 | 11 | #include "main.h" 12 | 13 | typedef struct { 14 | GPIO_TypeDef* CS_PORT; 15 | uint16_t CS_PIN; 16 | SPI_HandleTypeDef* hspi; 17 | }MCP3008_SPI; 18 | 19 | void MCP3008_Init(MCP3008_SPI* spi, SPI_HandleTypeDef* hspi, GPIO_TypeDef* CS_PORT, uint16_t CS_PIN); 20 | uint16_t MCP3008_Read_Channel(MCP3008_SPI* spi, uint8_t channel); 21 | 22 | #endif /* MCP3008_MCP3008_H_ */ 23 | -------------------------------------------------------------------------------- /Encoder/Encoder.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Encoder.h 3 | * 4 | * Created on: 23 juil. 2020 5 | * Author: Daniel Mårtensson 6 | */ 7 | 8 | #ifndef SRC_ENCODER_ENCODER_H_ 9 | #define SRC_ENCODER_ENCODER_H_ 10 | 11 | #include "main.h" 12 | 13 | typedef struct{ 14 | uint8_t dir; 15 | uint16_t cnt1, cnt2, diff, speed, one_rotation_pulses; 16 | uint32_t tick; 17 | TIM_HandleTypeDef* htim; 18 | }Encoder; 19 | 20 | void Encoder_init(Encoder *encoder, TIM_HandleTypeDef *htim, uint16_t one_rotation_pulses); 21 | void Encoder_count(Encoder *encoder); 22 | float Encoder_getSpeed(Encoder *encoder); 23 | uint16_t Encoder_getDifference(Encoder *encoder); 24 | 25 | #endif /* SRC_ENCODER_ENCODER_H_ */ 26 | -------------------------------------------------------------------------------- /Optimized ILI9341 Touch LCD/Touch Screen/Logics/One_button_logic.c: -------------------------------------------------------------------------------- 1 | /* 2 | * One_button_logic.c 3 | * 4 | * Created on: 24 juli 2021 5 | * Author: Daniel Mårtensson 6 | */ 7 | 8 | #include "../Touch_screen.h" 9 | #include "../Hardware/ILI9341.h" 10 | 11 | uint8_t STM32_PLC_LCD_Call_One_Button_Logic(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2) { 12 | while (1) { 13 | if (TSC2046_isPressed()) { 14 | TSC2046_GetTouchData(); 15 | uint16_t X = lcd.myTsData.X; 16 | uint16_t Y = lcd.myTsData.Y; 17 | if (X >= x1 && X <= x2 && Y >= y1 && Y <= y2) { 18 | ILI9341_hollow_rect(x1, y1, x2, y2, COLOR_MAGENTA); 19 | return 1; /* Button 1 */ 20 | } 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /FlashMemory_F3/ReadWrite.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ReadWrite.h 3 | * 4 | * Created on: Dec 10, 2020 5 | * Author: Daniel Mårtensson 6 | */ 7 | 8 | #ifndef SRC_FLASHMEMORY_F3_READWRITE_H_ 9 | #define SRC_FLASHMEMORY_F3_READWRITE_H_ 10 | 11 | #include "main.h" 12 | 13 | //Typedefs 14 | //1. data size 15 | typedef enum{ 16 | DATA_TYPE_U64=0, 17 | DATA_TYPE_U16, 18 | DATA_TYPE_U32, 19 | DATA_TYPE_FLOAT 20 | }DataTypeDef; 21 | 22 | // Converter for float <--> uint8_t 23 | typedef union{ 24 | float float_value; 25 | uint8_t uint8_values[sizeof(float)]; 26 | }Convert; 27 | 28 | // Set memory address 29 | void FlashSetAddrs(uint32_t address); 30 | // Write Flash 31 | void FlashWriteN(uint32_t idx, void *wrBuf, uint32_t Nsize, DataTypeDef dataType); 32 | // Read Flash 33 | void FlashReadN(uint32_t idx, void *rdBuf, uint32_t Nsize, DataTypeDef dataType); 34 | 35 | #endif /* SRC_FLASHMEMORY_F3_READWRITE_H_ */ 36 | -------------------------------------------------------------------------------- /FlashMemory_F3/ReadMe.md: -------------------------------------------------------------------------------- 1 | This is a simple library for writing and reading to the flash memory for STM32 F3-series. This is NOT an EEPROM library, but it works as the same. 2 | 3 | Program example: 4 | 5 | ``` 6 | // Include 7 | #include "FlashMemory_F3/ReadWrite.h" 8 | 9 | // Set the sector and the address - They can be found in the data sheet of your processor. Look at chapter 3.2.1 at document RM0313 for STM32F37XXX processors 10 | FlasheSetAddrs(0x0803F800); // We take the last sector for the main memory and begin to write at the first address 11 | 12 | // Write 13 | float wrBuf[7] = {value1, value2, pressure_value, speed, setpoint, horizon, forgetting}; 14 | FlashWriteN(0, wrBuf, 7, DATA_TYPE_FLOAT); // Begin to write at index 0 and write 7 float values 15 | 16 | // Read 17 | uint16_t TIM_PRESCALES[4] = {0}; 18 | uint32_t Nsize = sizeof(TIM_PRESCALES)/sizeof(TIM_PRESCALES[0]); 19 | FlashReadN(0, TIM_PRESCALES, Nsize, DATA_TYPE_U16); 20 | ``` 21 | -------------------------------------------------------------------------------- /Optimized ILI9341 Touch LCD/Touch Screen/Logics/Two_button_logic.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Two_button_logic.c 3 | * 4 | * Created on: Jul 23, 2021 5 | * Author: Daniel Mårtensson 6 | */ 7 | 8 | #include "../Touch_screen.h" 9 | #include "../Hardware/ILI9341.h" 10 | 11 | uint8_t STM32_PLC_LCD_Call_Two_Button_Logic(uint16_t b1_x1, uint16_t b1_y1, uint16_t b1_x2, uint16_t b1_y2, uint16_t b2_x1, uint16_t b2_y1, uint16_t b2_x2, uint16_t b2_y2) { 12 | while (1) { 13 | if (TSC2046_isPressed()) { 14 | TSC2046_GetTouchData(); 15 | uint16_t X = lcd.myTsData.X; 16 | uint16_t Y = lcd.myTsData.Y; 17 | if (X >= b1_x1 && X <= b1_x2 && Y >= b1_y1 && Y <= b1_y2) { 18 | ILI9341_hollow_rect(b1_x1, b1_y1, b1_x2, b1_y2, COLOR_MAGENTA); 19 | return 1; /* Button 1 */ 20 | } else if (X >= b2_x1 && X <= b2_x2 && Y >= b2_y1 && Y <= b2_y2) { 21 | ILI9341_hollow_rect(b2_x1, b2_y1, b2_x2, b2_y2, COLOR_MAGENTA); 22 | return 0; /* Button 2 */ 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /HX711 Load Cell Amplifier/ReadMe.md: -------------------------------------------------------------------------------- 1 | # HX711 Load Cell 24-bit Amplifier 2 | This is a load cell amplifier with 24-bit resolution. I have rewrite Arduino C++ to STM32 C code from [bogde](https://github.com/bogde/HX711). 3 | This library works great with STM32. 4 | 5 | Program example: 6 | 7 | ``` 8 | // Include 9 | #include "main.h" 10 | #include "HX711/HX711.h" 11 | 12 | // Structure 13 | HX711 hx; 14 | 15 | int main(void) 16 | { 17 | // PD_SCK is digital output 18 | // DOUT is digital input with a pull-up resistor activated 19 | HX711_begin(&hx, HX711_PD_SCK_GPIO_Port, HX711_PD_SCK_Pin, HX711_DOUT_GPIO_Port, HX711_DOUT_Pin, 128); 20 | HX711_set_scale(&hx, 2280.f); // Set scale 21 | HX711_tare(&hx, 0); // Reset scale to 0 22 | 23 | while (1) 24 | { 25 | float value = HX711_get_units(&hx, 10); 26 | char text[20]; 27 | sprintf(text, "%f", value); // Don't forget to enable -u _printf_float flag in the settings 28 | } 29 | } 30 | ``` 31 | -------------------------------------------------------------------------------- /MAX31865/MAX31865.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef MAX31865_LIB_MAX31865_H 3 | #define MAX31865_LIB_MAX31865_H 4 | 5 | #include "main.h" 6 | 7 | // Sensor defines 8 | #define MAX31865_RREF 430 // Reference resistor 9 | #define MAX31865_FACTOR 32768 // 2^15 used for data to resistance conversion 10 | #define MAX31865_ALPHA 0.003851 // PT-100 temperature coefficient 11 | 12 | // User defines 13 | #define WIRE4 4 14 | #define WIRE3 3 15 | #define WIRE2 2 16 | 17 | typedef struct { 18 | GPIO_TypeDef* CE_PORT; 19 | uint16_t CE_PIN; 20 | SPI_HandleTypeDef* hspi; 21 | uint8_t WIRES; 22 | } MAX31865_SPI; 23 | 24 | void MAX31865_init(MAX31865_SPI* spi, GPIO_TypeDef* CE_PORT, uint16_t CE_PIN, SPI_HandleTypeDef* hspi, uint8_t WIRES); 25 | float MAX31865_temperature(MAX31865_SPI* spi); 26 | uint8_t MAX31865_configuration(MAX31865_SPI* spi); 27 | uint16_t MAX31865_raw_resistance(MAX31865_SPI* spi); 28 | #endif //MAX31865_LIB_MAX31865_H 29 | -------------------------------------------------------------------------------- /Encoder/ReadMe.md: -------------------------------------------------------------------------------- 1 | # Encoder 2 | With this, you can measure velocity, direction and also count the position for an encoder. 3 | 4 | Settings: 5 | 6 | Don't forget to use pull-down resistors at `GPIO Settings->GPIO Pull-up/Pull-down` 7 | 8 | ![a](https://github.com/DanielMartensson/STM32-Libraries/blob/master/Encoder/S%C3%A9lection_064.png) 9 | 10 | Program example: 11 | 12 | ``` 13 | // Includes 14 | #include "main.h" 15 | #include "Encoder/Encoder.h" 16 | 17 | // Structures 18 | TIM_HandleTypeDef htim5; 19 | Encoder encoder; 20 | 21 | int main(){ 22 | /* Regular STM32 stuffs */ 23 | 24 | // Init encoder that have 30 pulses for each rotation 25 | HAL_TIM_Encoder_Start(&htim5, TIM_CHANNEL_ALL); 26 | Encoder_init(&encoder, &htim5, 30); 27 | 28 | while(1){ 29 | Encoder_count(&encoder); 30 | float speed = Encoder_getSpeed(&encoder)/30.0; // Unit: RPM 31 | float difference = Encoder_getDifference(&encoder); 32 | HAL_Delay(1); 33 | } 34 | 35 | } 36 | ``` 37 | -------------------------------------------------------------------------------- /FlashMemory/ReadWrite.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ReadWrite.h 3 | * 4 | * Created on: Jul 5, 2020 5 | * Author: Daniel Mårtensson 6 | */ 7 | 8 | #ifndef SRC_FLASHMEMORY_READWRITE_H_ 9 | #define SRC_FLASHMEMORY_READWRITE_H_ 10 | 11 | #include "main.h" 12 | 13 | //Typedefs 14 | //1. data size 15 | typedef enum{ 16 | DATA_TYPE_U8=0, 17 | DATA_TYPE_U16, 18 | DATA_TYPE_U32, 19 | DATA_TYPE_FLOAT 20 | }DataTypeDef; 21 | 22 | // Converter for float <--> uint8_t 23 | typedef union{ 24 | float float_value; 25 | uint8_t uint8_values[sizeof(float)]; 26 | }Convert; 27 | 28 | //functions prototypes 29 | //1. Erase Sector 30 | void FlashEraseSector(); 31 | //2. Set Sector Adress 32 | void FlashSetSectorAddrs(uint8_t sector, uint32_t addrs); 33 | //3. Write Flash 34 | void FlashWriteN(uint32_t idx, void *wrBuf, uint32_t Nsize, DataTypeDef dataType); 35 | //4. Read Flash 36 | void FlashReadN(uint32_t idx, void *rdBuf, uint32_t Nsize, DataTypeDef dataType); 37 | 38 | #endif /* SRC_FLASHMEMORY_READWRITE_H_ */ 39 | -------------------------------------------------------------------------------- /FlashMemory_F4/ReadWrite.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ReadWrite.h 3 | * 4 | * Created on: Jul 5, 2020 5 | * Author: Daniel Mårtensson 6 | */ 7 | 8 | #ifndef SRC_FLASHMEMORY_READWRITE_H_ 9 | #define SRC_FLASHMEMORY_READWRITE_H_ 10 | 11 | #include "main.h" 12 | 13 | //Typedefs 14 | //1. data size 15 | typedef enum{ 16 | DATA_TYPE_U8=0, 17 | DATA_TYPE_U16, 18 | DATA_TYPE_U32, 19 | DATA_TYPE_FLOAT 20 | }DataTypeDef; 21 | 22 | // Converter for float <--> uint8_t 23 | typedef union{ 24 | float float_value; 25 | uint8_t uint8_values[sizeof(float)]; 26 | }Convert; 27 | 28 | //functions prototypes 29 | //1. Erase Sector 30 | void FlashEraseSector(); 31 | //2. Set Sector Adress 32 | void FlashSetSectorAddrs(uint8_t sector, uint32_t addrs); 33 | //3. Write Flash 34 | void FlashWriteN(uint32_t idx, void *wrBuf, uint32_t Nsize, DataTypeDef dataType); 35 | //4. Read Flash 36 | void FlashReadN(uint32_t idx, void *rdBuf, uint32_t Nsize, DataTypeDef dataType); 37 | 38 | #endif /* SRC_FLASHMEMORY_READWRITE_H_ */ 39 | -------------------------------------------------------------------------------- /ILI9341 Touch LCD/LCDTools/LCDTools.h: -------------------------------------------------------------------------------- 1 | /* 2 | * LCDTools.h 3 | * 4 | * Created on: May 22, 2020 5 | * Author: Daniel Mårtensson 6 | */ 7 | 8 | 9 | #ifndef SRC_LCD_ILI9341_LCDTOOLS_LCDTOOLS_H_ 10 | #define SRC_LCD_ILI9341_LCDTOOLS_LCDTOOLS_H_ 11 | 12 | #include "stdbool.h" 13 | #include // For sprintf 14 | #include // For memset 15 | #include "../LCDCore/LCD_ILI9341.h" 16 | #include "pictures.h" 17 | #include "printf.h" 18 | #include "cmsis_os.h" 19 | 20 | void show_main_frame(ILI9341_SPI* spi, bool closedloop_on, bool update_main_frame, bool identification_on); 21 | uint8_t show_num_pad_frame(ILI9341_SPI* spi, bool decimalbutton_show, bool minusbutton_show, float* number_value, char* title); 22 | void show_plot_frame(ILI9341_SPI *spi, float new_input_float, float new_output_float, uint16_t new_input_uint, uint16_t new_output_uint, bool only_move_array, bool clear_plot); 23 | uint8_t show_question_save_settings_dialog(ILI9341_SPI *spi); 24 | 25 | 26 | #endif /* SRC_LCD_ILI9341_LCDTOOLS_LCDTOOLS_H_ */ 27 | -------------------------------------------------------------------------------- /ADS1015_ADS1115/ReadMe.md: -------------------------------------------------------------------------------- 1 | # ADS1015 and ADS1115 ADC 16 bit 2 | 3 | This is a powerful ADC of 16 bit resolution. It has 4 channels and communicating with STM32 through the I2C bus. 4 | I recommend this due to its high resolution and cheap price. This library follows the same as Adafruit library of the same 5 | ADC. 6 | 7 | Program example: 8 | 9 | ``` 10 | // Include 11 | #include "ADS1015_ADS1115/ADS1015_ADS1115.h" 12 | 13 | // Structures 14 | I2C_HandleTypeDef hi2c1; 15 | ADS1xx5_I2C i2c; 16 | 17 | // Declare the structure where we using GND as address. 18 | // Look at the top of the header file for addresses. 19 | ADS1115(&i2c, &hi2c1, ADS_ADDR_GND); // Or ADS1015(&i2c, &hi2c1, ADS_ADDR_GND); 20 | ADSsetGain(&i2c, GAIN_EIGHT); 21 | 22 | while(){ 23 | // Get ADC values 24 | int16_t adc0, adc1, adc2, adc3; 25 | 26 | adc0 = ADSreadADC_SingleEnded(&i2c, 0); 27 | adc1 = ADSreadADC_SingleEnded(&i2c, 1); 28 | adc2 = ADSreadADC_SingleEnded(&i2c, 2); 29 | adc3 = ADSreadADC_SingleEnded(&i2c, 3); 30 | } 31 | ``` 32 | -------------------------------------------------------------------------------- /Optimized ILI9341 Touch LCD/Touch Screen/Frames/Tools/Intro_frame.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Intro_frame.c 3 | * 4 | * Created on: Jul 23, 2021 5 | * Author: Daniel Mårtensson 6 | */ 7 | 8 | #include "../../Touch_screen.h" 9 | #include "../../Hardware/ILI9341.h" 10 | 11 | void STM32_PLC_LCD_Show_Intro_Frame() { 12 | ILI9341_set_rotation(2); 13 | ILI9341_fill_screen(COLOR_WHITE); 14 | 15 | /* Do the 80's style introduction */ 16 | uint16_t colors[7] = {(uint16_t) COLOR_RED, (uint16_t) COLOR_GREEN, (uint16_t) COLOR_CYAN, (uint16_t) COLOR_BLUE, (uint16_t) COLOR_MAGENTA, (uint16_t) COLOR_NAVY, (uint16_t) COLOR_ORANGE }; 17 | for (uint8_t i = 0; i < sizeof(colors) / sizeof(colors[0]); i++) { 18 | uint16_t x0 = 10 * (i + 1); 19 | uint16_t y0 = 10 * (i + 1); 20 | uint16_t x1 = ILI9341_HEIGHT - 19 * (i + 1); 21 | uint16_t y1 = ILI9341_WIDTH - 19 * (i + 1); 22 | ILI9341_fill_rect(x0, y0, x1, y1, colors[i]); 23 | ILI9341_hollow_rect(x0, y0, x1, y1, COLOR_BLACK); 24 | } 25 | ILI9341_print_text("STM32 PLC", 74, 80, COLOR_BLACK, COLOR_ORANGE, 2); 26 | HAL_Delay(1000); 27 | } 28 | 29 | -------------------------------------------------------------------------------- /SSD1306 128x32/SSD1306.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SSD1306.h 3 | * 4 | * Created on: 4 juin 2020 5 | * Author: Daniel Mårtensson 6 | */ 7 | 8 | #ifndef SRC_SSD1306_128X32_SSD1306_H_ 9 | #define SRC_SSD1306_128X32_SSD1306_H_ 10 | 11 | #include "stdbool.h" 12 | #include "main.h" 13 | #include "stdlib.h" 14 | #define SSD1306_swap(a, b) { int16_t t = a; a = b; b = t; } 15 | 16 | void SSD1306_init(I2C_HandleTypeDef *i2c); 17 | void SSD1306_invert_display(bool invert); 18 | void SSD1306_start_scroll_right(uint8_t start, uint8_t stop); 19 | void SSD1306_start_scroll_left(uint8_t start, uint8_t stop); 20 | void SSD1306_start_scroll_diagonal_right(uint8_t start, uint8_t stop); 21 | void SSD1306_start_scroll_diagonal_left(uint8_t start, uint8_t stop); 22 | void SSD1306_stop_scroll(); 23 | void SSD1306_dim(uint8_t dim); 24 | void SSD1306_draw_line(uint8_t x0, uint8_t x1, uint8_t y0, uint8_t y1); 25 | void SSD1306_write_text(char* str, uint8_t x, uint8_t y); 26 | void SSD1306_write_bitmap(uint8_t x, uint8_t y, uint8_t* bitmap, uint8_t rows, uint8_t columns); 27 | 28 | #endif /* SRC_SSD1306_128X32_SSD1306_H_ */ 29 | -------------------------------------------------------------------------------- /FlashMemory/ReadMe.md: -------------------------------------------------------------------------------- 1 | This is a simple library for writing and reading to the flash memory. This is NOT an EEPROM library, but it works as the same. 2 | 3 | Program example: 4 | 5 | ``` 6 | // Include 7 | #include "FlashMemory/ReadWrite.h" 8 | 9 | // Set the sector and the address - They can be found in the data sheet of your processor. Look at chapter 3.3 at document RM0390 for STM32F446XX processors 10 | FlashSetSectorAddrs(7, 0x08060000); // We take the last sector for the main memory and begin to write at the first address 11 | 12 | // Write 13 | float wrBuf[7] = {value1, value2, pressure_value, speed, setpoint, horizon, forgetting}; 14 | FlashEraseSector(); // Must clear first 15 | FlashWriteN(0, wrBuf, 7, DATA_TYPE_FLOAT); // Begin to write at index 0 and write 7 float values 16 | 17 | // Read 18 | float rdBuf[7]; 19 | FlashReadN(0, rdBuf, 7, DATA_TYPE_FLOAT); // Begin at index 0 and read 7 float values 20 | float value1 = rdBuf[0]; 21 | float value2 = rdBuf[1]; 22 | float pressure_value = rdBuf[2]; 23 | float speed = rdBuf[3]; 24 | float setpoint = rdBuf[4]; 25 | float horizon = rdBuf[5]; 26 | float forgetting = rdBuf[6]; 27 | ``` 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Daniel Mårtensson 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /MCP23017/ReadMe.md: -------------------------------------------------------------------------------- 1 | # MCP23017 IO-Expander 16-bit 2 | This is a very powerfull IO-expander that can handle interrupts, inputs and digital outputs. This library follows the 3 | same command for the Arduino library. Use this if you have few I/O-pins left or you don't want to waste pins on a LCD 4 | or something. 5 | 6 | Program example: 7 | 8 | ``` 9 | // Include 10 | #include "MCP23017/MCP23017.h" 11 | 12 | // Structs 13 | I2C_HandleTypeDef hi2c1; 14 | MCP23017_I2C mcp_i2c; 15 | 16 | // Init 17 | MCP23017begin(&mcp_i2c, &hi2c1, 0x00); // There is an address table in the comment of this function. 18 | MCP23017pinMode(&mcp_i2c, 0, MCP23017_OUTPUT); 19 | 20 | // Set to high 21 | MCP23017digitalWrite(&mcp_i2c, 0, MCP23017_HIGH); // GPA0 = Pin ID 0 22 | ``` 23 | 24 | Physial Pin #| Pin Name | Pin ID 25 | ----|------|------------------------------ 26 | 21 | GPA0 | 0 27 | 22 | GPA1 | 1 28 | 23 | GPA2 | 2 29 | 24 | GPA3 | 3 30 | 25 | GPA4 | 4 31 | 26 | GPA5 | 5 32 | 27 | GPA6 | 6 33 | 28 | GPA7 | 7 34 | 1 | GPB0 | 8 35 | 2 | GPB1 | 9 36 | 3 | GPB2 | 10 37 | 4 | GPB3 | 11 38 | 5 | GPB4 | 12 39 | 6 | GPB5 | 13 40 | 7 | GPB6 | 14 41 | 8 | GPB7 | 15 42 | -------------------------------------------------------------------------------- /FlashMemory_F4/ReadMe.md: -------------------------------------------------------------------------------- 1 | This is a simple library for writing and reading to the flash memory for the STM32 F4-series. This is NOT an EEPROM library, but it works as the same. 2 | 3 | Program example: 4 | 5 | ``` 6 | // Include 7 | #include "FlashMemory_F4/ReadWrite.h" 8 | 9 | // Set the sector and the address - They can be found in the data sheet of your processor. Look at chapter 3.3 at document RM0390 for STM32F446XX processors 10 | FlashSetSectorAddrs(7, 0x08060000); // We take the last sector for the main memory and begin to write at the first address 11 | 12 | // Write 13 | float wrBuf[7] = {value1, value2, pressure_value, speed, setpoint, horizon, forgetting}; 14 | FlashEraseSector(); // Must clear first 15 | FlashWriteN(0, wrBuf, 7, DATA_TYPE_FLOAT); // Begin to write at index 0 and write 7 float values 16 | 17 | // Read 18 | float rdBuf[7]; 19 | FlashReadN(0, rdBuf, 7, DATA_TYPE_FLOAT); // Begin at index 0 and read 7 float values 20 | float value1 = rdBuf[0]; 21 | float value2 = rdBuf[1]; 22 | float pressure_value = rdBuf[2]; 23 | float speed = rdBuf[3]; 24 | float setpoint = rdBuf[4]; 25 | float horizon = rdBuf[5]; 26 | float forgetting = rdBuf[6]; 27 | ``` 28 | -------------------------------------------------------------------------------- /DS3231/DS3231/DS3231.h: -------------------------------------------------------------------------------- 1 | /* 2 | * DS3231.h 3 | * 4 | * Created on: 6 mars 2020 5 | * Author: Daniel Mårtensson 6 | */ 7 | 8 | #ifndef SRC_DS3231_DS3231_H_ 9 | #define SRC_DS3231_DS3231_H_ 10 | 11 | #include "main.h" 12 | #include "stdbool.h" 13 | 14 | typedef struct { 15 | uint8_t addr; /* Address of the RTC */ 16 | I2C_HandleTypeDef *hi2c; /* Handler for the I2C */ 17 | uint8_t second; 18 | uint8_t minute; 19 | uint8_t hour; 20 | uint8_t day; 21 | uint8_t date; 22 | uint8_t month; 23 | uint8_t year; 24 | }DS3231_I2C; 25 | 26 | void DS3231_init(DS3231_I2C* i2c, I2C_HandleTypeDef* hi2c, uint8_t addr,uint8_t enableWeekAlarm, uint8_t enableDateAlarm); 27 | void DS3231_setClock(DS3231_I2C* i2c, uint8_t seconds, uint8_t minutes, uint8_t hours, uint8_t days, uint8_t dates, uint8_t months, uint8_t years); 28 | void DS3231_getClock(DS3231_I2C* i2c); 29 | void DS3231_setDateAlarm(DS3231_I2C* i2c, uint8_t seconds, uint8_t minutes, uint8_t hours, uint8_t dates); 30 | void DS3231_setWeekAlarm(DS3231_I2C* i2c, uint8_t minutes, uint8_t hours, uint8_t days); 31 | void DS3231_offTriggAlarm(DS3231_I2C* i2c); 32 | uint8_t DS3231_readALarmStatus(DS3231_I2C* i2c); 33 | 34 | #endif /* SRC_DS3231_DS3231_H_ */ 35 | -------------------------------------------------------------------------------- /MCP4728/mcp4728.h: -------------------------------------------------------------------------------- 1 | /* 2 | * mcp4728.h 3 | * 4 | * Created on: May 1, 2022 5 | * Author: Daniel Mårtensson 6 | */ 7 | 8 | #ifndef SRC_MCP4728_MCP4728_H_ 9 | #define SRC_MCP4728_MCP4728_H_ 10 | 11 | #include "main.h" 12 | #include 13 | 14 | #define MCP4728_CHANNEL_A 0x0 15 | #define MCP4728_CHANNEL_B 0x1 16 | #define MCP4728_CHANNEL_C 0x2 17 | #define MCP4728_CHANNEL_D 0x3 18 | #define MCP4728_VREF_VDD 0x0 19 | #define MCP4728_VREF_INTERNAL 0x1 20 | #define MCP4728_POWER_DOWN_NORMAL 0x0 21 | #define MCP4728_POWER_DOWN_1K 0x1 22 | #define MCP4728_POWER_DOWN_100K 0x2 23 | #define MCP4728_POWER_DOWN_500K 0x3 24 | #define MCP4728_GAIN_1 0x0 25 | #define MCP4728_GAIN_2 0x1 26 | 27 | void mcp4728_init(I2C_HandleTypeDef *hi2c, uint8_t address); 28 | void mcp4728_set_channel_value(uint8_t channel, uint16_t value); 29 | void mcp4728_set_channel_power_down(uint8_t channel, uint8_t power_down); 30 | void mcp4728_set_channel_gain(uint8_t channel, uint8_t gain); 31 | void mcp4728_set_channel_vref(uint8_t channel, uint8_t vref); 32 | void mcp4728_multi_write_command(); 33 | void mcp4728_single_write_command(uint8_t channel); 34 | 35 | #endif /* SRC_MCP4728_MCP4728_H_ */ 36 | -------------------------------------------------------------------------------- /MCP3008/ReadMe.md: -------------------------------------------------------------------------------- 1 | # MCP3008 8-Channel 10-Bit ADC 2 | Written STM32 C-library. This is a 10-Bit ADC with 8 channels. Use this if you want to have a potentiometer or something analog like a joystick because this ADC is very stable. This ADC does not fit measurements. Please use another ADC with higher bit resolution e.g ADS1115. 3 | 4 | Program example: 5 | 6 | ``` 7 | // Include 8 | #include "MCP3008/MCP3008.h" 9 | 10 | // Structs 11 | MCP3008_SPI spi_mpc3008; 12 | SPI_HandleTypeDef hspi2; 13 | 14 | /* 15 | * SPI settings: 16 | * CPHA = 1 Edge 17 | * Prescaler = 8 18 | * First bit = MBS first 19 | * CPOL = Low 20 | */ 21 | // Init the 10-Bit ADC 22 | MCP3008_Init(&spi_mpc3008, &hspi2, GPIOA, GPIO_PIN_8); 23 | 24 | // Read ADC's 25 | uint16_t adc0 = MCP3008_Read_Channel(&spi, 0); // Channel 0 26 | uint16_t adc1 = MCP3008_Read_Channel(&spi, 1); // Channel 1 27 | uint16_t adc2 = MCP3008_Read_Channel(&spi, 2); // Channel 2 28 | uint16_t adc3 = MCP3008_Read_Channel(&spi, 3); // Channel 3 29 | uint16_t adc4 = MCP3008_Read_Channel(&spi, 4); // Channel 4 30 | uint16_t adc5 = MCP3008_Read_Channel(&spi, 5); // Channel 5 31 | uint16_t adc6 = MCP3008_Read_Channel(&spi, 6); // Channel 6 32 | uint16_t adc7 = MCP3008_Read_Channel(&spi, 7); // Channel 7 33 | ``` 34 | -------------------------------------------------------------------------------- /Optimized ILI9341 Touch LCD/Touch Screen/Dialogs/Information_ok_dialog.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Information_ok_dialog.c 3 | * 4 | * Created on: 24 juli 2021 5 | * Author: Daniel Mårtensson 6 | */ 7 | 8 | #include "../Touch_screen.h" 9 | #include "../Hardware/ILI9341.h" 10 | 11 | uint8_t STM32_PLC_LCD_Show_Information_OK_Dialog(char information[]) { 12 | ILI9341_set_rotation(2); 13 | 14 | /* Big blue frame */ 15 | ILI9341_fill_rect(40, 80, 290, 160, COLOR_BLUE); 16 | ILI9341_hollow_rect(40, 80, 290, 160, COLOR_BLACK); 17 | 18 | /* White big frame */ 19 | ILI9341_fill_rect(42, 82, 288, 158, COLOR_WHITE); 20 | ILI9341_hollow_rect(42, 82, 288, 158, COLOR_BLACK); 21 | 22 | /* Small question background frame */ 23 | ILI9341_fill_rect(45, 85, 285, 106, COLOR_BLUE); 24 | ILI9341_hollow_rect(45, 85, 285, 106, COLOR_BLACK); 25 | 26 | /* Text */ 27 | ILI9341_print_text("Information", 105, 88, COLOR_BLACK, COLOR_BLUE, 2); 28 | ILI9341_print_text(information, 50, 110, COLOR_BLACK, COLOR_WHITE, 1); 29 | 30 | /* OK button */ 31 | ILI9341_fill_rect(145, 129, 180, 150, COLOR_LGRAY); 32 | ILI9341_hollow_rect(145, 129, 180, 150, COLOR_BLACK); 33 | ILI9341_print_text("OK", 152, 132, COLOR_BLACK, COLOR_LGRAY, 2); 34 | 35 | /* Logic */ 36 | return STM32_PLC_LCD_Call_One_Button_Logic(145, 129, 180, 150); 37 | } 38 | -------------------------------------------------------------------------------- /MAX31865/ReadMe.md: -------------------------------------------------------------------------------- 1 | # MAX31865 RTD Temperature reader 2 | 3 | This library is made for the MAX31865 ADC with Software SPI connection. When this library, you can connect a 2/3/4 wire RTD temperature sensor and read its temperature. 4 | 5 | This library has been tested with Nucleo-F446RE. 6 | 7 | Program example: 8 | ``` 9 | // Include 10 | #include "MAX31865/MAX31865.h" 11 | 12 | // Structs 13 | SPI_HandleTypeDef hspi2; 14 | MAX31865_SPI spi0; 15 | MAX31865_SPI spi1; 16 | MAX31865_SPI spi2; 17 | 18 | /* 19 | * SPI settings: 20 | * CPHA = 2 Edge 21 | * Prescaler = 256 22 | * First bit = MBS first 23 | * CPOL = High 24 | */ 25 | 26 | // Select WIRE4 for 4 wire PT100 or WIRE3 for 3 wire PT100 or WIRE2 for 2 wire PT100 27 | // You can use this for PT1000 as well, just change the reference value in MAX31865.h file 28 | 29 | // Temperature sensors 30 | MAX31865_init(&spi0, GPIOB, GPIO_PIN_14, &hspi2, WIRE4); // 14 = CE0 31 | MAX31865_init(&spi1, GPIOB, GPIO_PIN_15, &hspi2, WIRE4); // 15 = CE1 32 | MAX31865_init(&spi2, GPIOB, GPIO_PIN_12, &hspi2, WIRE4); // 12 = CE2 33 | 34 | // Print temperature 35 | float temperature0 = MAX31865_temperature(&spi0); 36 | float temperature1 = MAX31865_temperature(&spi1); 37 | float temperature2 = MAX31865_temperature(&spi2); 38 | ``` 39 | -------------------------------------------------------------------------------- /MCP3008/MCP3008.c: -------------------------------------------------------------------------------- 1 | /* 2 | * MCP3008.c 3 | * 4 | * Created on: 14 Feb 2020 5 | * Author: Daniel Mårtensson 6 | */ 7 | 8 | #include "MCP3008.h" 9 | 10 | /* 11 | * Set the MISO, MOSI, SCK and CS 12 | * SPI settings: 13 | * CPHA = 1 Edge 14 | * Prescaler = 8 15 | * First bit = MBS first 16 | * CPOL = Low 17 | */ 18 | void MCP3008_Init(MCP3008_SPI* spi, SPI_HandleTypeDef* hspi, GPIO_TypeDef* CS_PORT, uint16_t CS_PIN){ 19 | spi->hspi = hspi; 20 | spi->CS_PORT = CS_PORT; 21 | spi->CS_PIN = CS_PIN; 22 | } 23 | 24 | // Read the channels from 0 to 7 25 | uint16_t MCP3008_Read_Channel(MCP3008_SPI* spi, uint8_t channel){ 26 | 27 | // Declare data that we will send 28 | uint8_t pTxData[3] = {0}; 29 | pTxData[0] = ((0x01 << 7)| // start bit 30 | (1 << 6)| // SGL 31 | ((channel & 0x07) << 3)); // channel number 32 | pTxData[1] = 0x00; 33 | pTxData[2] = 0x00; 34 | 35 | // Data that we will get 36 | uint8_t pRxData[3] = {0}; 37 | 38 | // CS low, Send and receive, CS high 39 | HAL_GPIO_WritePin(spi->CS_PORT, spi->CS_PIN, GPIO_PIN_RESET); 40 | HAL_SPI_TransmitReceive(spi->hspi, pTxData, pRxData, 3, 10); 41 | HAL_GPIO_WritePin(spi->CS_PORT, spi->CS_PIN, GPIO_PIN_SET); 42 | 43 | // Compute the ADC 44 | return 0x3FF & ((pRxData[0] & 0x01) << 9 | (pRxData[1] & 0xFF) << 1 | (pRxData[2] & 0x80) >> 7); 45 | } 46 | -------------------------------------------------------------------------------- /Micro SD SPI/fatfs_sd.h: -------------------------------------------------------------------------------- 1 | #ifndef __FATFS_SD_H 2 | #define __FATFS_SD_H 3 | 4 | /* Definitions for MMC/SDC command */ 5 | #define CMD0 (0x40+0) /* GO_IDLE_STATE */ 6 | #define CMD1 (0x40+1) /* SEND_OP_COND */ 7 | #define CMD8 (0x40+8) /* SEND_IF_COND */ 8 | #define CMD9 (0x40+9) /* SEND_CSD */ 9 | #define CMD10 (0x40+10) /* SEND_CID */ 10 | #define CMD12 (0x40+12) /* STOP_TRANSMISSION */ 11 | #define CMD16 (0x40+16) /* SET_BLOCKLEN */ 12 | #define CMD17 (0x40+17) /* READ_SINGLE_BLOCK */ 13 | #define CMD18 (0x40+18) /* READ_MULTIPLE_BLOCK */ 14 | #define CMD23 (0x40+23) /* SET_BLOCK_COUNT */ 15 | #define CMD24 (0x40+24) /* WRITE_BLOCK */ 16 | #define CMD25 (0x40+25) /* WRITE_MULTIPLE_BLOCK */ 17 | #define CMD41 (0x40+41) /* SEND_OP_COND (ACMD) */ 18 | #define CMD55 (0x40+55) /* APP_CMD */ 19 | #define CMD58 (0x40+58) /* READ_OCR */ 20 | 21 | void SD_init_handler(SPI_HandleTypeDef* hspi_, GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); 22 | DSTATUS SD_disk_initialize (BYTE pdrv); 23 | DSTATUS SD_disk_status (BYTE pdrv); 24 | DRESULT SD_disk_read (BYTE pdrv, BYTE* buff, DWORD sector, UINT count); 25 | DRESULT SD_disk_write (BYTE pdrv, const BYTE* buff, DWORD sector, UINT count); 26 | DRESULT SD_disk_ioctl (BYTE pdrv, BYTE cmd, void* buff); 27 | 28 | #define SPI_TIMEOUT 1000 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /Optimized ILI9341 Touch LCD/Touch Screen/Frames/Measurement_and_time_frame.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Measurement_and_time_frame.c 3 | * 4 | * Created on: Jul 23, 2021 5 | * Author: Daniel Mårtensson 6 | */ 7 | 8 | #include "../Touch_screen.h" 9 | #include "../Hardware/ILI9341.h" 10 | #include "../../Functions.h" 11 | 12 | void STM32_PLC_LCD_Show_Measurement_And_Time_Frame(uint8_t *frame_id) { 13 | /* Clear the screen , but not the icons */ 14 | ILI9341_fill_rect(51, 6, 314, 234, COLOR_NAVY); 15 | 16 | /* Write the title */ 17 | ILI9341_draw_horizontal_line(50, 30, 265, COLOR_GREEN); 18 | ILI9341_print_text("Measurement values and time", 55, 10, COLOR_YELLOW, COLOR_NAVY, 1); 19 | 20 | /* Exit button */ 21 | ILI9341_fill_rect(85, 205, 273, 230, COLOR_GREEN); 22 | ILI9341_hollow_rect(85, 205, 273, 230, COLOR_BLACK); 23 | ILI9341_print_text("Exit frame now", 95, 210, COLOR_BLACK, COLOR_GREEN, 2); 24 | 25 | while(1) { 26 | /* Show the values */ 27 | STM32_PLC_LCD_Show_Plot_Frame(); 28 | 29 | /* Logic for button */ 30 | if (TSC2046_isPressed()) { 31 | TSC2046_GetTouchData(); 32 | uint16_t X = lcd.myTsData.X; 33 | uint16_t Y = lcd.myTsData.Y; 34 | if (X >= 85 && X <= 273 && Y >= 205 && Y <= 230) { 35 | ILI9341_hollow_rect(85, 205, 273, 230, COLOR_MAGENTA); 36 | break; 37 | } 38 | } 39 | } 40 | 41 | /* Exit */ 42 | STM32_PLC_LCD_Show_Main_Frame(frame_id, false); 43 | } 44 | -------------------------------------------------------------------------------- /LiquidCrystal I2C/ReadMe.md: -------------------------------------------------------------------------------- 1 | # Liquid Crystal with I2C 2 | 3 | This library is made for the PCF8574/PCF8574A expander IC with I2C connection. With this library, you can write to liquid crystals 4 | displays such as 16x2 LCD or 20x4 LCD. Notice that this example is using GPIOA PIN5 as a check-led if the I2C connected the expander IC. Change function init_priv(LCD* lcd) in LiquidCrystal_I2C.c if you want to change that pin. 5 | 6 | This library has been tested with Nucleo-F446RE. 7 | 8 | Program example: 9 | ``` 10 | // Include 11 | #include "LiquidCrystal_I2C/LiquidCrystal_I2C.h" 12 | 13 | // LCD defines 14 | #define ADDRESS 0x4E // Write to LCD 15 | #define COLS 20 16 | #define ROWS 4 17 | 18 | // Structs 19 | LiquidCrystal_LCD lcd0; 20 | I2C_HandleTypeDef hi2c1; 21 | 22 | // LCD 20x4 23 | LiquidCrystal_I2C(&lcd0, &hi2c1, ADDRESS, COLS, ROWS); 24 | init(&lcd0); 25 | clear(&lcd0); 26 | home(&lcd0); 27 | char* str = "Hej August!"; 28 | printToLCD(&lcd0, str, 11); 29 | blink_on(&lcd0); 30 | setCursor(&lcd0, 8, 2); 31 | char* str2 = "Hej ITH!"; 32 | printToLCD(&lcd0, str2, 8); 33 | ``` 34 | 35 | Hint: If you don't know, the C function sprintf can be used to turn a float value to a string. If you want to display float values on a STM32, then you need to add (Atollic TrueSTUDIO is used): -u _printf_float 36 | 37 | ![a](https://raw.githubusercontent.com/DanielMartensson/STM32-Libraries/master/LiquidCrystal%20I2C/Selecci%C3%B3n_020.png) 38 | -------------------------------------------------------------------------------- /DS3231/ReadMe.md: -------------------------------------------------------------------------------- 1 | # DS3231 RTC with 2 alarm 2 | This is an easy RTC with very high accuracy in time. You can use this if you want to connect a larm of week or date with it. 3 | Perhaps both. This is much better than the low budget RTC DS1307. The output pin SQW will become HIGH when no alarms exist. SQW pin will become LOW when an alarm appear or all alarms are activated. Then you can make sure that if SQW is HIGH, then the RTC is still alive. 4 | 5 | Program example: 6 | 7 | ``` 8 | //Include 9 | #include "main.h" 10 | #include "DS3231/DS3231.h" 11 | 12 | // Structures 13 | I2C_HandleTypeDef hi2c1; 14 | DS3231_I2C DS_i2c; 15 | 16 | // Init RTC - Set larm for: Week = false, Date = true and also the address 0x00 17 | DS3231_init(&DS_i2c, &hi2c1, 0x0, false, true); 18 | // Set the clock - Second 55. Hour 12. Day 5(Friday). Day of month 6. Month of year 3 (Mars). Year 2020. 19 | DS3231_setClock(&DS_i2c, 55, 59, 12, 5, 6, 3, 20); 20 | // Set alarm for the week - Minute 0. Hour 13. Day 5 21 | DS3231_setWeekAlarm(&DS_i2c, 0, 13, 5); 22 | // Sett alarm for the month 23 | DS3231_setDateAlarm(&DS_i2c, 15, 0, 13, 6); 24 | 25 | while(1){ 26 | // Get the time and the status of booth alarms 27 | DS3231_getClock(&DS_i2c); 28 | uint8_t status = DS3231_readALarmStatus(&DS_i2c); 29 | char text2[50]; 30 | sprintf(text2, "HH:%d,MM:%d,SS:%d,S:%d", DS_i2c.hour, DS_i2c.minute, DS_i2c.second, status); 31 | 32 | // Shut off the alarm with a trigg - It will start again when the time has come again 33 | DS3231_offTriggAlarm(&DS_i2c); 34 | } 35 | 36 | ``` 37 | -------------------------------------------------------------------------------- /VL6180X/Distribution/VL6180X_Distribution.m: -------------------------------------------------------------------------------- 1 | % Read the log 2 | close all 3 | fid = csvread('log.txt')'; 4 | 5 | % Initial lists 6 | X = zeros(1, max(fid) + 5); % We add 5 just to have some extra columns of zero 7 | sampels_for_every_mean = 50; 8 | count = 1; 9 | meanvalues = []; 10 | stdvalues = []; 11 | collection = zeros(1, sampels_for_every_mean); 12 | for i = 1:length(fid) 13 | 14 | % Get the value from the log and place it into the list X, depending on what kind of value. 15 | % Here we only measureing the frequency how often a specific value appears 16 | value = fid(i); 17 | X(value) = X(value) + 1; 18 | 19 | % Collect the values 20 | collection(count) = value; 21 | 22 | % For every sampels_for_every_mean:th intervall, do mean and std 23 | if(count >= sampels_for_every_mean) 24 | meanvalues = [meanvalues mean(collection)]; 25 | stdvalues = [stdvalues std(collection)]; 26 | 27 | % Reset 28 | count = 1; 29 | else 30 | count = count + 1; % Count 31 | end 32 | end 33 | 34 | % Distribution 35 | bar(X/sum(X)) 36 | xlim([(min(fid)-5) (max(fid)+5)]) 37 | grid on 38 | title(sprintf('Distribution where total samples are %i', length(fid))) 39 | ylabel('Propability') 40 | xlabel('value') 41 | 42 | % Mean 43 | figure 44 | plot(meanvalues) 45 | grid on 46 | title(sprintf('Mean over time where mean count is %i', sampels_for_every_mean)) 47 | ylabel('Mean') 48 | xlabel('Time') 49 | 50 | % Std 51 | figure 52 | plot(stdvalues) 53 | grid on 54 | title(sprintf('Std over time where std count is %i', sampels_for_every_mean)) 55 | ylabel('Std') 56 | xlabel('Time') 57 | -------------------------------------------------------------------------------- /Optimized ILI9341 Touch LCD/Touch Screen/Dialogs/Question_yes_no_dialog.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Question_dialog_yes_no.c 3 | * 4 | * Created on: Jul 23, 2021 5 | * Author: Daniel Mårtensson 6 | */ 7 | 8 | #include "../Touch_screen.h" 9 | #include "../Hardware/ILI9341.h" 10 | 11 | uint8_t STM32_PLC_LCD_Show_Question_Yes_No_Dialog(char question[]) { 12 | ILI9341_set_rotation(2); 13 | 14 | /* Big blue frame */ 15 | ILI9341_fill_rect(40, 80, 290, 160, COLOR_BLUE); 16 | ILI9341_hollow_rect(40, 80, 290, 160, COLOR_BLACK); 17 | 18 | /* White big frame */ 19 | ILI9341_fill_rect(42, 82, 288, 158, COLOR_WHITE); 20 | ILI9341_hollow_rect(42, 82, 288, 158, COLOR_BLACK); 21 | 22 | /* Small question background frame */ 23 | ILI9341_fill_rect(45, 85, 285, 106, COLOR_BLUE); 24 | ILI9341_hollow_rect(45, 85, 285, 106, COLOR_BLACK); 25 | 26 | /* Text */ 27 | ILI9341_print_text("Question", 115, 88, COLOR_BLACK, COLOR_BLUE, 2); 28 | ILI9341_print_text(question, 50, 110, COLOR_BLACK, COLOR_WHITE, 1); 29 | 30 | /* Yes button */ 31 | ILI9341_fill_rect(120, 129, 160, 150, COLOR_LGRAY); 32 | ILI9341_hollow_rect(120, 129, 160, 150, COLOR_BLACK); 33 | ILI9341_print_text("Yes", 122, 132, COLOR_BLACK, COLOR_LGRAY, 2); 34 | 35 | /* No button */ 36 | ILI9341_fill_rect(168, 129, 208, 150, COLOR_LGRAY); 37 | ILI9341_hollow_rect(168, 129, 208, 150, COLOR_BLACK); 38 | ILI9341_print_text("No", 176, 132, COLOR_BLACK, COLOR_LGRAY, 2); 39 | 40 | /* Logic */ 41 | uint8_t b1_x1 = 120; 42 | uint8_t b1_y1 = 129; 43 | uint8_t b1_x2 = 160; 44 | uint8_t b1_y2 = 150; 45 | uint8_t b2_x1 = 168; 46 | uint8_t b2_y1 = 129; 47 | uint8_t b2_x2 = 208; 48 | uint8_t b2_y2 = 150; 49 | return STM32_PLC_LCD_Call_Two_Button_Logic(b1_x1, b1_y1, b1_x2, b1_y2, b2_x1, b2_y1, b2_x2, b2_y2); 50 | } 51 | -------------------------------------------------------------------------------- /MCP4728/ReadMe.md: -------------------------------------------------------------------------------- 1 | MCP4728 is a 12-bit DAC. It's working. Notice that you need to use LDAC pin too. Connect it to your STM32 GPIO and name it `LDAC` only or connect it to `GND`. 2 | Don't forget pull-up resistors for the I2C SDA and SCL. You can activate internal pull-ups in the STM32 processor for I2C. 3 | 4 | ```c 5 | 6 | /* Include */ 7 | #include "MCP4728/mcp4728.h" 8 | 9 | /* Handler */ 10 | I2C_HandleTypeDef hi2c1; 11 | 12 | /* Write to MCP4728 */ 13 | mcp4728_init(&hi2c1, 0x4); // Manufacturer I2C settings: A4 (A2 = 1, A1 = 0, A0 = 0) 14 | 15 | /* Set values */ 16 | mcp4728_set_channel_value(MCP4728_CHANNEL_A, 4095); 17 | mcp4728_set_channel_value(MCP4728_CHANNEL_B, 1000); 18 | mcp4728_set_channel_value(MCP4728_CHANNEL_C, 2000); 19 | mcp4728_set_channel_value(MCP4728_CHANNEL_D, 3000); 20 | 21 | /* Set gain */ 22 | mcp4728_set_channel_gain(MCP4728_CHANNEL_A, MCP4728_GAIN_1); 23 | mcp4728_set_channel_gain(MCP4728_CHANNEL_B, MCP4728_GAIN_1); 24 | mcp4728_set_channel_gain(MCP4728_CHANNEL_C, MCP4728_GAIN_1); 25 | mcp4728_set_channel_gain(MCP4728_CHANNEL_D, MCP4728_GAIN_1); 26 | 27 | /* Set power down */ 28 | mcp4728_set_channel_power_down(MCP4728_CHANNEL_A, MCP4728_POWER_DOWN_NORMAL); 29 | mcp4728_set_channel_power_down(MCP4728_CHANNEL_B, MCP4728_POWER_DOWN_NORMAL); 30 | mcp4728_set_channel_power_down(MCP4728_CHANNEL_C, MCP4728_POWER_DOWN_NORMAL); 31 | mcp4728_set_channel_power_down(MCP4728_CHANNEL_D, MCP4728_POWER_DOWN_NORMAL); 32 | 33 | /* Set voltage reference */ 34 | mcp4728_set_channel_vref(MCP4728_CHANNEL_A, MCP4728_VREF_VDD); 35 | mcp4728_set_channel_vref(MCP4728_CHANNEL_B, MCP4728_VREF_VDD); 36 | mcp4728_set_channel_vref(MCP4728_CHANNEL_C, MCP4728_VREF_VDD); 37 | mcp4728_set_channel_vref(MCP4728_CHANNEL_D, MCP4728_VREF_VDD); 38 | 39 | /* Multi write without EEPROM */ 40 | mcp4728_multi_write_command(); 41 | 42 | /* Single write with EEPROM */ 43 | mcp4728_set_channel_value(MCP4728_CHANNEL_A, 1000); 44 | mcp4728_single_write_command(MCP4728_CHANNEL_A); 45 | ``` 46 | 47 | -------------------------------------------------------------------------------- /SSD1306 128x32/ReadMe.md: -------------------------------------------------------------------------------- 1 | # SSD1306 128x32 2 | This is a simple OLED LCD that have two colors only. Use this LCD if you want to show something simple like a number or display 3 | a tiny plot. Notice that this LCD can only have one address. So only one SSD1306 128x32 per project. Connection I2C. 4 | 5 | Program example: 6 | 7 | ``` 8 | // include 9 | #include "main.h" 10 | #include "SSD1306 128x32/SSD1306.h" 11 | 12 | // Struct 13 | I2C_HandleTypeDef hi2c1; 14 | 15 | // Code 16 | SSD1306_init(&hi2c1); 17 | SSD1306_draw_line(0, 15, 0, 3); 18 | SSD1306_dim(true); 19 | SSD1306_write_text("Megaman!1", 15, 15); 20 | uint8_t megaman32x32[] = {0x00,0x00,0x00,0x00 21 | ,0x00,0x00,0x00,0x00 22 | ,0x00,0x00,0xe0,0x00 23 | ,0x00,0x0f,0x30,0x00 24 | ,0x00,0x1f,0xc0,0x00 25 | ,0x00,0x1f,0xc0,0x00 26 | ,0x00,0x1f,0xde,0x00 27 | ,0x00,0x7f,0xe2,0x00 28 | ,0x00,0x7f,0xfe,0x00 29 | ,0x00,0x7f,0xfe,0x00 30 | ,0x00,0x7f,0x12,0x00 31 | ,0x00,0x1f,0x12,0x00 32 | ,0x00,0x1f,0xfe,0x00 33 | ,0x00,0xce,0x0c,0x00 34 | ,0x00,0xe6,0x0c,0x00 35 | ,0x07,0xf7,0xf3,0xc0 36 | ,0x07,0xf8,0x0f,0xc0 37 | ,0x0f,0xff,0xf7,0xe0 38 | ,0x0f,0x9f,0xf3,0xe0 39 | ,0x0c,0x1f,0xf0,0x60 40 | ,0x0f,0x1f,0xf1,0xe0 41 | ,0x0f,0x1f,0xf1,0xe0 42 | ,0x0f,0x1f,0xf1,0xe0 43 | ,0x00,0x1f,0xf0,0x00 44 | ,0x00,0x7f,0xfc,0x00 45 | ,0x00,0xfe,0xfe,0x00 46 | ,0x00,0xfe,0xfe,0x00 47 | ,0x00,0xf8,0x3e,0x00 48 | ,0x07,0xf0,0x1f,0xc0 49 | ,0x1f,0xf0,0x1f,0xf0 50 | ,0x1f,0xf0,0x1f,0xf0 51 | ,0x00,0x00,0x00,0x00}; 52 | SSD1306_write_bitmap(70, 0, megaman32x32, 32, 4); 53 | SSD1306_start_scroll_diagonal_right(0, 8); 54 | ``` 55 | -------------------------------------------------------------------------------- /MCP23017/MCP23017.h: -------------------------------------------------------------------------------- 1 | /* 2 | * MCP23017.h 3 | * 4 | * Created on: 9 févr. 2020 5 | * Author: Adafruit, Rewritten by Daniel Mårtensson 6 | */ 7 | 8 | #ifndef SRC_MCP23017_MCP23017_H_ 9 | #define SRC_MCP23017_MCP23017_H_ 10 | 11 | #include "main.h" 12 | 13 | typedef struct { 14 | uint8_t i2caddr; 15 | I2C_HandleTypeDef *hi2c; // Handle for I2C 16 | } MCP23017_I2C; 17 | 18 | void MCP23017begin(MCP23017_I2C* i2c, I2C_HandleTypeDef* hi2c, uint8_t addr); 19 | 20 | 21 | void MCP23017pinMode(MCP23017_I2C* i2c, uint8_t p, uint8_t d); 22 | void MCP23017digitalWrite(MCP23017_I2C* i2c, uint8_t p, uint8_t d); 23 | void MCP23017pullUp(MCP23017_I2C* i2c, uint8_t p, uint8_t d); 24 | uint8_t MCP23017digitalRead(MCP23017_I2C* i2c, uint8_t p); 25 | 26 | void MCP23017writeGPIOAB(MCP23017_I2C* i2c, uint16_t); 27 | uint16_t MCP23017readGPIOAB(MCP23017_I2C* i2c); 28 | uint8_t MCP23017readGPIO(MCP23017_I2C* i2c, uint8_t b); 29 | 30 | void MCP23017setupInterrupts(MCP23017_I2C* i2c, uint8_t mirroring, uint8_t open, uint8_t polarity); 31 | void MCP23017setupInterruptPin(MCP23017_I2C* i2c, uint8_t p, uint8_t mode); 32 | uint8_t MCP23017getLastInterruptPin(MCP23017_I2C* i2c); 33 | uint8_t MCP23017getLastInterruptPinValue(MCP23017_I2C* i2c); 34 | 35 | 36 | #define MCP23017bitRead(value, bit) (((value) >> (bit)) & 0x01) 37 | #define MCP23017bitSet(value, bit) ((value) |= (1UL << (bit))) 38 | #define MCP23017bitClear(value, bit) ((value) &= ~(1UL << (bit))) 39 | #define MCP23017bitWrite(value, bit, bitvalue) (bitvalue ? MCP23017bitSet(value, bit) : MCP23017bitClear(value, bit)) 40 | 41 | #define MCP23017_ADDRESS 0x20 42 | 43 | // registers 44 | #define MCP23017_IODIRA 0x00 45 | #define MCP23017_IPOLA 0x02 46 | #define MCP23017_GPINTENA 0x04 47 | #define MCP23017_DEFVALA 0x06 48 | #define MCP23017_INTCONA 0x08 49 | #define MCP23017_IOCONA 0x0A 50 | #define MCP23017_GPPUA 0x0C 51 | #define MCP23017_INTFA 0x0E 52 | #define MCP23017_INTCAPA 0x10 53 | #define MCP23017_GPIOA 0x12 54 | #define MCP23017_OLATA 0x14 55 | 56 | #define MCP23017_IODIRB 0x01 57 | #define MCP23017_IPOLB 0x03 58 | #define MCP23017_GPINTENB 0x05 59 | #define MCP23017_DEFVALB 0x07 60 | #define MCP23017_INTCONB 0x09 61 | #define MCP23017_IOCONB 0x0B 62 | #define MCP23017_GPPUB 0x0D 63 | #define MCP23017_INTFB 0x0F 64 | #define MCP23017_INTCAPB 0x11 65 | #define MCP23017_GPIOB 0x13 66 | #define MCP23017_OLATB 0x15 67 | 68 | #define MCP23017_INT_ERR 255 69 | 70 | #define MCP23017_CHANGE 0 71 | #define MCP23017_FALLING 1 72 | #define MCP23017_RISING 0 73 | #define MCP23017_HIGH 1 74 | #define MCP23017_LOW 0 75 | #define MCP23017_INPUT 0 76 | #define MCP23017_OUTPUT 1 77 | 78 | #endif /* SRC_MCP23017_MCP23017_H_ */ 79 | -------------------------------------------------------------------------------- /Encoder/Encoder.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Encoder.c 3 | * 4 | * Created on: 23 juil. 2020 5 | * Author: Daniel Mårtensson 6 | */ 7 | 8 | #include "Encoder.h" 9 | 10 | /* 11 | * Use a timer and select combined channels -> Encoder Mode. 12 | * Then select our prescaler and the counter period 13 | * Then select Encoder Mode TI1 and TI2. 14 | * Leave the rest as default 15 | */ 16 | void Encoder_init(Encoder *encoder, TIM_HandleTypeDef *htim, uint16_t one_rotation_pulses) { 17 | encoder->htim = htim; 18 | encoder->one_rotation_pulses = one_rotation_pulses; 19 | } 20 | 21 | void Encoder_count(Encoder *encoder) { 22 | if (HAL_GetTick() - encoder->tick > 1000L) { 23 | /* Control TIM for every check_every_ms */ 24 | encoder->cnt2 = encoder->htim->Instance->CNT; 25 | 26 | /* Control the rotation count */ 27 | if (__HAL_TIM_IS_TIM_COUNTING_DOWN(encoder->htim)) { 28 | encoder->dir = 1; 29 | /* __HAL_TIM_IS_TIM_COUNTING_DOWN Exception when the macro is wrong configured */ 30 | if ((encoder->cnt2 > encoder->cnt1) && (encoder->cnt2 - encoder->cnt1 < 100)) 31 | encoder->dir = 0; 32 | } else { 33 | encoder->dir = 0; 34 | /* __HAL_TIM_IS_TIM_COUNTING_DOWN Excepting when the macro gives error */ 35 | if ((encoder->cnt1 > encoder->cnt2) && (encoder->cnt1 - encoder->cnt2 < 100)) 36 | encoder->dir = 1; 37 | } 38 | 39 | if (encoder->dir) { 40 | /* Down Counting */ 41 | if (encoder->cnt1 >= encoder->cnt2) 42 | encoder->diff = encoder->cnt1 - encoder->cnt2; 43 | else 44 | encoder->diff = (encoder->htim->Instance->ARR + encoder->cnt1) - encoder->cnt2; 45 | } else { 46 | /* Up Counting */ 47 | if (encoder->cnt2 >= encoder->cnt1) 48 | encoder->diff = encoder->cnt2 - encoder->cnt1; 49 | else 50 | encoder->diff = (encoder->htim->Instance->ARR + encoder->cnt2) - encoder->cnt1; 51 | } 52 | 53 | if ((encoder->htim->Instance->SMCR & 0x03) == 0x03) { 54 | /* X4 Mode Countering increase with 4 Pulse */ 55 | encoder->speed = encoder->diff * 60 / 4 / encoder->one_rotation_pulses; //RPM x 60 56 | } else { 57 | /* X4 Mode Countering increase with 2 Pulse */ 58 | encoder->speed = encoder->diff * 60 / 2 / encoder->one_rotation_pulses; //RPM x 60 59 | } 60 | 61 | encoder->tick = HAL_GetTick(); 62 | encoder->cnt1 = encoder->htim->Instance->CNT; 63 | } 64 | } 65 | 66 | // Get the speed and also the direction - Unit: RPM*one_rotation_pulses 67 | float Encoder_getSpeed(Encoder *encoder){ 68 | return encoder->dir == 1 ? (float) encoder->speed : -((float) encoder->speed); 69 | } 70 | 71 | // Get the difference for every check 72 | uint16_t Encoder_getDifference(Encoder *encoder){ 73 | return encoder->diff; 74 | } 75 | -------------------------------------------------------------------------------- /VL6180X/ReadMe.md: -------------------------------------------------------------------------------- 1 | This is VL6180X distance + ALS sensor. VL6180 works too for this library because it's the same sensor, without the ALS sensor. 2 | This code uses the same code from Adafruit, because I just rewrote Arduino C++ code to STM32 C code. 3 | 4 | This sensor have a very high accuracy for the price. about 1-2mm accuracy between 10-100mm. Have a look at the distribution folder for calculation how good VL6180X is. 5 | 6 | Notice that to get a higher precision, then add an Unscented Kalman Filter. 7 | https://github.com/DanielMartensson/CControl 8 | 9 | Program example: 10 | ``` 11 | #include "main.h" 12 | #include "VL6180X/VL6180X.h" 13 | 14 | // Structures 15 | I2C_HandleTypeDef hi2c1; 16 | 17 | VL6180X_Init(&hi2c1); 18 | 19 | uint8_t mode = 0; 20 | /* USER CODE END 2 */ 21 | 22 | /* Infinite loop */ 23 | /* USER CODE BEGIN WHILE */ 24 | while (1) 25 | { 26 | /* USER CODE END WHILE */ 27 | float lux = VL6180X_readLux(VL6180X_ALS_GAIN_5); 28 | range = VL6180X_readRange(); 29 | uint8_t status = VL6180X_readRangeStatus(); 30 | 31 | if (status == VL6180X_ERROR_NONE) { 32 | mode = 1; 33 | } 34 | 35 | // Some error occurred, print it out! 36 | 37 | if ((status >= VL6180X_ERROR_SYSERR_1) && (status <= VL6180X_ERROR_SYSERR_5)) { 38 | mode = 2; 39 | } 40 | else if (status == VL6180X_ERROR_ECEFAIL) { 41 | mode = 3; 42 | } 43 | else if (status == VL6180X_ERROR_NOCONVERGE) { 44 | mode = 4; 45 | } 46 | else if (status == VL6180X_ERROR_RANGEIGNORE) { 47 | mode = 5; 48 | } 49 | else if (status == VL6180X_ERROR_SNR) { 50 | mode = 6; 51 | } 52 | else if (status == VL6180X_ERROR_RAWUFLOW) { 53 | mode = 7; 54 | } 55 | else if (status == VL6180X_ERROR_RAWOFLOW) { 56 | mode = 8; 57 | } 58 | else if (status == VL6180X_ERROR_RANGEUFLOW) { 59 | mode = 9; 60 | } 61 | else if (status == VL6180X_ERROR_RANGEOFLOW) { 62 | mode = 10; 63 | } 64 | HAL_Delay(50); 65 | } 66 | ``` 67 | 68 | Pictures of distance measurement(millimeter) at steady state e.g measuring at a fixed distance over time. 69 | 70 | ![a](https://raw.githubusercontent.com/DanielMartensson/STM32-Libraries/master/VL6180X/Distribution/Distribution.png) 71 | 72 | ![a](https://raw.githubusercontent.com/DanielMartensson/STM32-Libraries/master/VL6180X/Distribution/Mean.png) 73 | 74 | ![a](https://raw.githubusercontent.com/DanielMartensson/STM32-Libraries/master/VL6180X/Distribution/Std.png) 75 | 76 | Here is an example where I'm using a Kalman Filter example. C-code available at CControl repository. 77 | 78 | ![a](https://raw.githubusercontent.com/DanielMartensson/STM32-Libraries/master/VL6180X/UKF.png) 79 | -------------------------------------------------------------------------------- /Optimized ILI9341 Touch LCD/Touch Screen/Frames/Tools/Keyboard_frame.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Numpad_frame.c 3 | * 4 | * Created on: Jul 29, 2021 5 | * Author: Daniel Mårtensson 6 | */ 7 | 8 | #include "../../Touch_screen.h" 9 | #include "../../Hardware/ILI9341.h" 10 | 11 | uint8_t STM32_PLC_LCD_Show_Keyboard_Frame(char word[], char title[]) { 12 | /* Begin with black page */ 13 | ILI9341_fill_screen(COLOR_BLACK); 14 | 15 | /* Print frame - large square */ 16 | ILI9341_hollow_rect(5, 5, 315, 235, COLOR_GREEN); 17 | 18 | /* Create gray, white square */ 19 | ILI9341_fill_rect(6, 6, 314, 55, COLOR_DGRAY); 20 | ILI9341_fill_rect(12, 24, 308, 50, COLOR_WHITE); 21 | 22 | /* Set title */ 23 | ILI9341_print_text(title, 12, 12, COLOR_WHITE, COLOR_DGRAY, 1); 24 | 25 | /* Create buttons */ 26 | uint16_t x = 0; 27 | char letter[3]; 28 | uint8_t keyboard_page = 6; /* We start at this */ 29 | for (uint8_t i = 0; i < 5; i++) { 30 | x += 23; 31 | /* Upper numbers */ 32 | ILI9341_fill_rect(x, 70, x + 40, 110, COLOR_DGRAY); 33 | ILI9341_fill_rect(x + 5, 75, x + 35, 105, COLOR_WHITE); 34 | sprintf(letter, "%c", i + 32 + 5*keyboard_page); /* 32 is space char when i = 0 */ 35 | ILI9341_print_text(letter, x + 16, 83, COLOR_BLACK, COLOR_WHITE, 2); 36 | 37 | /* Lower numbers */ 38 | ILI9341_fill_rect(x, 125, x + 40, 165, COLOR_DGRAY); 39 | ILI9341_fill_rect(x + 5, 130, x + 35, 160, COLOR_WHITE); 40 | sprintf(letter, "%c", i + 5 + 32 + 5*keyboard_page); /* 32 + 5 is % char when i = 0 */ 41 | ILI9341_print_text(letter, x + 16, 138, COLOR_BLACK, COLOR_WHITE, 2); 42 | 43 | /* This show the < and > buttons */ 44 | if (i == 0) { 45 | ILI9341_fill_rect(x, 180, x + 40, 220, COLOR_DGRAY); 46 | ILI9341_fill_rect(x + 5, 185, x + 35, 215, COLOR_WHITE); 47 | } else if (i == 1) { 48 | ILI9341_fill_rect(x, 180, x + 40, 220, COLOR_DGRAY); 49 | ILI9341_fill_rect(x + 5, 185, x + 35, 215, COLOR_WHITE); 50 | } 51 | 52 | /* This show the <- and OK buttons */ 53 | if (i > 1) { 54 | ILI9341_fill_rect(x, 180, x + 40, 220, COLOR_DGRAY); 55 | ILI9341_fill_rect(x + 5, 185, x + 35, 215, COLOR_WHITE); 56 | } 57 | 58 | /* Give the buttons a text */ 59 | if (i == 0) { 60 | ILI9341_print_text("<", x + 15, 193, COLOR_BLACK, COLOR_WHITE, 2); 61 | } else if (i == 1) { 62 | ILI9341_print_text(">", x + 15, 193, COLOR_BLACK, COLOR_WHITE, 2); 63 | } else if (i == 2) { 64 | ILI9341_print_text("C", x + 15, 193, COLOR_BLACK, COLOR_WHITE, 2); 65 | } else if (i == 3) { 66 | ILI9341_print_text("<-", x + 9, 193, COLOR_BLACK, COLOR_WHITE, 2); 67 | } else if (i == 4) { 68 | ILI9341_print_text("OK", x + 9, 193, COLOR_BLACK, COLOR_WHITE, 2); 69 | } 70 | 71 | x += 35; /* Space between buttons */ 72 | } 73 | 74 | /* Logic */ 75 | return STM32_PLC_LCD_Call_Keyboard_Logic(word); 76 | } 77 | -------------------------------------------------------------------------------- /Optimized ILI9341 Touch LCD/Touch Screen/Frames/Tools/Numpad_frame.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Numpad_frame.c 3 | * 4 | * Created on: Jul 23, 2021 5 | * Author: Daniel Mårtensson 6 | */ 7 | 8 | #include "../../Touch_screen.h" 9 | #include "../../Hardware/ILI9341.h" 10 | 11 | uint8_t STM32_PLC_LCD_Show_Numpad_Frame(bool decimalbutton_show, bool minusbutton_show, float *number_value, char title[]) { 12 | /* Begin with black page */ 13 | ILI9341_fill_screen(COLOR_BLACK); 14 | 15 | /* Print frame - large square */ 16 | ILI9341_hollow_rect(5, 5, 315, 235, COLOR_GREEN); 17 | 18 | /* Create gray, white square */ 19 | ILI9341_fill_rect(6, 6, 314, 55, COLOR_DGRAY); 20 | ILI9341_fill_rect(12, 24, 308, 50, COLOR_WHITE); 21 | 22 | /* Set title */ 23 | ILI9341_print_text(title, 12, 12, COLOR_WHITE, COLOR_DGRAY, 1); 24 | 25 | /* Create buttons */ 26 | uint16_t x = 0; 27 | char number[3]; 28 | for (uint8_t i = 0; i < 5; i++) { 29 | x += 23; 30 | /* Upper numbers */ 31 | ILI9341_fill_rect(x, 70, x + 40, 110, COLOR_DGRAY); 32 | ILI9341_fill_rect(x + 5, 75, x + 35, 105, COLOR_WHITE); 33 | sprintf(number, "%d", i); 34 | ILI9341_print_text(number, x + 16, 83, COLOR_BLACK, COLOR_WHITE, 2); 35 | 36 | /* Lower numbers */ 37 | ILI9341_fill_rect(x, 125, x + 40, 165, COLOR_DGRAY); 38 | ILI9341_fill_rect(x + 5, 130, x + 35, 160, COLOR_WHITE); 39 | sprintf(number, "%d", i + 5); 40 | ILI9341_print_text(number, x + 16, 138, COLOR_BLACK, COLOR_WHITE, 2); 41 | 42 | /* This hide or show the buttons */ 43 | if (i == 0 && minusbutton_show == true) { 44 | ILI9341_fill_rect(x, 180, x + 40, 220, COLOR_DGRAY); 45 | ILI9341_fill_rect(x + 5, 185, x + 35, 215, COLOR_WHITE); 46 | } else if (i == 1 && decimalbutton_show == true) { 47 | ILI9341_fill_rect(x, 180, x + 40, 220, COLOR_DGRAY); 48 | ILI9341_fill_rect(x + 5, 185, x + 35, 215, COLOR_WHITE); 49 | } 50 | 51 | /* This show the <- and OK buttons */ 52 | if (i > 1) { 53 | ILI9341_fill_rect(x, 180, x + 40, 220, COLOR_DGRAY); 54 | ILI9341_fill_rect(x + 5, 185, x + 35, 215, COLOR_WHITE); 55 | } 56 | 57 | /* Give the buttons a text */ 58 | if (i == 0 && minusbutton_show == true) { 59 | ILI9341_print_text("-", x + 15, 193, COLOR_BLACK, COLOR_WHITE, 2); 60 | } else if (i == 1 && decimalbutton_show == true) { 61 | ILI9341_print_text(".", x + 15, 193, COLOR_BLACK, COLOR_WHITE, 2); 62 | } else if (i == 2) { 63 | ILI9341_print_text("C", x + 15, 193, COLOR_BLACK, COLOR_WHITE, 2); 64 | } else if (i == 3) { 65 | ILI9341_print_text("<-", x + 9, 193, COLOR_BLACK, COLOR_WHITE, 2); 66 | } else if (i == 4) { 67 | ILI9341_print_text("OK", x + 9, 193, COLOR_BLACK, COLOR_WHITE, 2); 68 | } 69 | x += 35; /* Space between buttons */ 70 | } 71 | 72 | /* Logic */ 73 | *number_value = 0; 74 | return STM32_PLC_LCD_Call_Numpad_Logic(decimalbutton_show, minusbutton_show, number_value); 75 | } 76 | -------------------------------------------------------------------------------- /Optimized ILI9341 Touch LCD/Touch Screen/Frames/SAE J1939 Frames/SAE_J1939_Request_frame.c: -------------------------------------------------------------------------------- 1 | /* 2 | * SAE_J1939_Request_frame.c 3 | * 4 | * Created on: Jul 23, 2021 5 | * Author: Daniel Mårtensson 6 | */ 7 | 8 | #include "../../Touch_screen.h" 9 | #include "../../Hardware/ILI9341.h" 10 | #include "../../../Open SAE J1939/SAE J1939/SAE J1939 Enums/Enum_PGN.h" 11 | #include "../../../Open SAE J1939/SAE J1939/SAE J1939-21 Transport Layer/Transport_Layer.h" 12 | 13 | void STM32_PLC_LCD_Show_SAE_J1939_Request_Frame(J1939 *j1939, uint8_t *frame_id) { 14 | /* Clear the screen , but not the icons */ 15 | ILI9341_fill_rect(51, 6, 314, 234, COLOR_NAVY); 16 | 17 | /* Write the title */ 18 | ILI9341_draw_horizontal_line(50, 30, 265, COLOR_GREEN); 19 | ILI9341_print_text("Do a PGN request", 55, 10, COLOR_YELLOW, COLOR_NAVY, 1); 20 | 21 | /* Most commonly PGN requests */ 22 | ILI9341_print_text("Commonly PGN numbers:", 55, 35, COLOR_YELLOW, COLOR_NAVY, 1); 23 | ILI9341_print_text("Address claimed:60928 Software ID:65242", 55, 45, COLOR_YELLOW, COLOR_NAVY, 1); 24 | ILI9341_print_text("ECU ID:64965 Component ID:65295", 55, 55, COLOR_YELLOW, COLOR_NAVY, 1); 25 | ILI9341_print_text("DM1:65226 DM2:65227 DM3:65228", 55, 65, COLOR_YELLOW, COLOR_NAVY, 1); 26 | 27 | /* Request button */ 28 | ILI9341_fill_rect(85, 195, 273, 220, COLOR_GREEN); 29 | ILI9341_hollow_rect(85, 195, 273, 220, COLOR_BLACK); 30 | ILI9341_print_text("Enter a request", 90, 200, COLOR_BLACK, COLOR_GREEN, 2); 31 | 32 | /* Logic for request button */ 33 | STM32_PLC_LCD_Call_One_Button_Logic(85, 195, 273, 220); 34 | 35 | /* Ask the user if */ 36 | if(STM32_PLC_LCD_Show_Question_Yes_No_Dialog("Do you want to enter a PGN number?") == 0) { 37 | STM32_PLC_LCD_Show_Main_Frame(frame_id, false); 38 | return; 39 | } 40 | 41 | /* You entered choice 1 - Show numpad */ 42 | bool minusbutton_show = false; 43 | bool decimalbutton_show = false; 44 | float number_value; 45 | if(STM32_PLC_LCD_Show_Numpad_Frame(decimalbutton_show, minusbutton_show, &number_value, "Enter PGN number between 0 and 65535") == 0) { 46 | STM32_PLC_LCD_Show_Main_Frame(frame_id, false); 47 | return; 48 | } 49 | uint16_t PGN; 50 | if(number_value < 0) 51 | PGN = 0; 52 | else if(number_value > 0xFFFF) 53 | PGN = 0xFFFF; 54 | else 55 | PGN = (uint16_t) number_value; 56 | 57 | /* Enter address */ 58 | if(STM32_PLC_LCD_Show_Numpad_Frame(decimalbutton_show, minusbutton_show, &number_value, "Enter destination address 0 to 255") == 0) { 59 | STM32_PLC_LCD_Show_Main_Frame(frame_id, false); 60 | return; 61 | } 62 | uint8_t DA; 63 | if(number_value < 0) 64 | DA = 0; 65 | else if(number_value > 0xFF) 66 | DA = 0xFF; 67 | else 68 | DA = (uint8_t) number_value; 69 | 70 | /* Enter the request */ 71 | SAE_J1939_Send_Request(j1939, DA, PGN); 72 | 73 | /* Exit */ 74 | STM32_PLC_LCD_Show_Main_Frame(frame_id, false); 75 | } 76 | -------------------------------------------------------------------------------- /PCA9685 PWM Servo/ReadMe.md: -------------------------------------------------------------------------------- 1 | # PCA9685 PWM Servo driver 2 | This is a library for controlling 5V servos with the PCA9685 IC chip. This IC chip has 16 channels with 12-bit PWM. Works great 3 | for small servos. A good thing with this library is that this library share the same functions as Adafruit's PCA9685 library! 4 | 5 | Program example: 6 | ``` 7 | // Includes 8 | #include "main.h" 9 | #include "PCA9685 PWM Servo/PCA9685.h" 10 | 11 | 12 | // Defines 13 | #define SERVOMIN 150 // This is the 'minimum' pulse length count (out of 4096) 14 | #define SERVOMAX 600 // This is the 'maximum' pulse length count (out of 4096) 15 | #define USMIN 600 // This is the rounded 'minimum' microsecond length based on the minimum pulse of 150 16 | #define USMAX 2400 // This is the rounded 'maximum' microsecond length based on the maximum pulse of 600 17 | #define SERVO_FREQ 50 // Analog servos run at ~50 Hz updates 18 | #define SERVOS 1 // How many servos we have 19 | 20 | // Structures 21 | I2C_HandleTypeDef hi2c1; 22 | 23 | // Functions 24 | void setServoPulse(uint8_t n, float pulse) { 25 | 26 | float pulselength = 1000000; // 1,000,000 us per second 27 | pulselength /= SERVO_FREQ; // Analog servos run at ~60 Hz updates 28 | pulselength /= 4096; // 12 bits of resolution 29 | pulse *= 1000000; // convert input seconds to us 30 | pulse /= pulselength; 31 | PCA9685_setPWM(&i2c, n, 0, pulse); 32 | } 33 | uint8_t servonum = 0; 34 | 35 | int main(void) 36 | { 37 | // Configure 38 | PCA9685_begin(&i2c, &hi2c1, 0x80, 0); 39 | PCA9685_setOscillatorFrequency(&i2c, 27000000); 40 | PCA9685_setPWMFreq(&i2c, SERVO_FREQ); // Analog servos run at ~50 Hz updates 41 | 42 | while (1) 43 | { 44 | // Drive each servo one at a time using setPWM() 45 | for (uint16_t pulselen = SERVOMIN; pulselen < SERVOMAX; pulselen++) { 46 | PCA9685_setPWM(&i2c, servonum, 0, pulselen); 47 | } 48 | 49 | HAL_Delay(500); 50 | for (uint16_t pulselen = SERVOMAX; pulselen > SERVOMIN; pulselen--) { 51 | PCA9685_setPWM(&i2c, servonum, 0, pulselen); 52 | } 53 | 54 | HAL_Delay(500); 55 | 56 | // Drive each servo one at a time using writeMicroseconds(), it's not precise due to calculation rounding! 57 | // The writeMicroseconds() function is used to mimic the Arduino Servo library writeMicroseconds() behavior. 58 | for (uint16_t microsec = USMIN; microsec < USMAX; microsec++) { 59 | PCA9685_writeMicroseconds(&i2c, servonum, microsec); 60 | } 61 | 62 | HAL_Delay(500); 63 | for (uint16_t microsec = USMAX; microsec > USMIN; microsec--) { 64 | PCA9685_writeMicroseconds(&i2c, servonum, microsec); 65 | } 66 | 67 | HAL_Delay(500); 68 | 69 | servonum++; 70 | if (servonum >= SERVOS) 71 | servonum = 0; // Testing the first SERVOS servo channels 72 | } 73 | } 74 | ``` 75 | -------------------------------------------------------------------------------- /MCP4728/mcp4728.c: -------------------------------------------------------------------------------- 1 | #include "mcp4728.h" 2 | 3 | static I2C_HandleTypeDef *_hi2c; 4 | static uint8_t _address; 5 | #define Timeout 10 6 | 7 | #define GERNAL_CALL_COMMAND 0x0 8 | #define GENERAL_CALL_RESET 0x6 9 | #define GENERAL_CALL_WAKE_UP 0x9 10 | #define SINGLE_WRITE_COMMAND 0xB 11 | #define MULTI_WRITE_COMMAND 0x8 12 | 13 | static uint16_t channel_value[4] = {0}; 14 | static uint8_t channel_power_down[4] = {0}; 15 | static uint8_t channel_gain[4] = {0}; 16 | static uint8_t channel_vref[4] = {0}; 17 | 18 | void static transmit_reset(){ 19 | uint8_t pData[1] = {GENERAL_CALL_RESET}; 20 | HAL_I2C_Master_Transmit(_hi2c, GERNAL_CALL_COMMAND, pData, sizeof(pData), Timeout); 21 | } 22 | 23 | void static transmit_wake_up(){ 24 | uint8_t pData[1] = {GENERAL_CALL_WAKE_UP}; 25 | HAL_I2C_Master_Transmit(_hi2c, GERNAL_CALL_COMMAND, pData, sizeof(pData), Timeout); 26 | } 27 | 28 | void mcp4728_init(I2C_HandleTypeDef *hi2c, uint8_t address){ 29 | _hi2c = hi2c; 30 | _address = (0xC << 3) | address; 31 | transmit_reset(); 32 | transmit_wake_up(); 33 | HAL_GPIO_WritePin(LDAC_GPIO_Port, LDAC_Pin, GPIO_PIN_RESET); 34 | } 35 | 36 | void mcp4728_set_channel_value(uint8_t channel, uint16_t value){ 37 | if(channel <= MCP4728_CHANNEL_D) 38 | channel_value[channel] = value; 39 | } 40 | 41 | void mcp4728_set_channel_power_down(uint8_t channel, uint8_t power_down){ 42 | if(channel <= MCP4728_CHANNEL_D) 43 | channel_power_down[channel] = power_down; 44 | } 45 | 46 | void mcp4728_set_channel_gain(uint8_t channel, uint8_t gain){ 47 | if(channel <= MCP4728_CHANNEL_D) 48 | channel_gain[channel] = gain; 49 | } 50 | 51 | void mcp4728_set_channel_vref(uint8_t channel, uint8_t vref){ 52 | if(channel <= MCP4728_CHANNEL_D) 53 | channel_vref[channel] = vref; 54 | } 55 | 56 | void mcp4728_multi_write_command(){ 57 | const uint8_t UDAC = 0x0; 58 | for(uint8_t channel = MCP4728_CHANNEL_A; channel <= MCP4728_CHANNEL_D; channel++){ 59 | uint8_t multi_write_data[3] = {(MULTI_WRITE_COMMAND << 3) | (channel << 1) | UDAC, (channel_vref[channel] << 7) | (channel_power_down[channel] << 5) | (channel_gain[channel] << 4) | (channel_value[channel] >> 8), channel_value[channel]}; 60 | HAL_I2C_Master_Transmit(_hi2c, _address << 1, multi_write_data, sizeof(multi_write_data), Timeout); 61 | } 62 | } 63 | 64 | void mcp4728_single_write_command(uint8_t channel){ 65 | /* This command should only be called with a time delay about 50 ms due to the EEPROM writing */ 66 | if(channel <= MCP4728_CHANNEL_D){ 67 | const uint8_t UDAC = 0x0; 68 | uint8_t pData[3] = {(SINGLE_WRITE_COMMAND << 3) | (channel << 1) | UDAC, (channel_vref[channel] << 7) | (channel_power_down[channel] << 5) | (channel_gain[channel] << 4) | (channel_value[channel] >> 8), channel_value[channel]}; 69 | HAL_I2C_Master_Transmit(_hi2c, _address << 1, pData, sizeof(pData), Timeout); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /nRF24L01 Radio RX-TX/ReadMe.md: -------------------------------------------------------------------------------- 1 | # nRF24L01 / nRF24L01+ Radio Transmitter and Receiver 2 | 3 | This is a very popular and robust radio and transmitter and reciever. This can be used with STM32 boards and it works fine. 4 | I don't know what to say any more, rather than it can send data by using SPI channel. 5 | I have rewritten this from ![MYaqoobEmbedded](https://github.com/MYaqoobEmbedded/STM32-Tutorials/tree/master/Tutorial%2024%20-%20NRF24L01%20Radio%20Transceiver) 6 | so it can be used with same SPI line. I have't change anything in his logic, only made it possible for using structs as objects. I have also made some simplifications in this library like having only two files. 7 | 8 | Program example: 9 | 10 | ``` 11 | // Includes 12 | #include "nRF24L01/nRF24L01.h" 13 | 14 | // Handles 15 | SPI_HandleTypeDef hspi2; 16 | UART_HandleTypeDef huart2; 17 | NRF24L01_SPI spi_rx; 18 | NRF24L01_SPI spi_tx; 19 | 20 | // Global variables 21 | uint64_t pipeAddress = 0x11223344AA; 22 | char myRxData[50]; 23 | char myAckPayload[32] = "Ack by STM32 Daniel!"; 24 | char myTxData[32] = "Hello World To You!"; 25 | char AckPayload[32]; 26 | 27 | /* Do setup for RX */ 28 | NRF24_begin(&spi_rx, GPIOA, CSN_RX_Pin, CE_RX_Pin, &hspi2); // Notice that CSN_RX and CE_RX need to have the same port 29 | nrf24_DebugUART_Init(&spi_rx, &huart2); 30 | 31 | // Print radio settings for RX 32 | printRadioSettings(&spi_rx); 33 | NRF24_setAutoAck(&spi_rx, true); 34 | NRF24_setChannel(&spi_rx, 52); 35 | NRF24_setPayloadSize(&spi_rx, 32); 36 | NRF24_openReadingPipe(&spi_rx, 1, pipeAddress); 37 | NRF24_enableDynamicPayloads(&spi_rx); 38 | NRF24_enableAckPayload(&spi_rx); 39 | NRF24_startListening(&spi_rx); 40 | 41 | /* Do setup for TX */ 42 | NRF24_begin(&spi_tx, GPIOA, CSN_TX_Pin, CE_TX_Pin, &hspi2); 43 | nrf24_DebugUART_Init(&spi_tx, &huart2); 44 | 45 | // Print radio settings for TX 46 | printRadioSettings(&spi_tx); 47 | 48 | /* Do setup for TX */ 49 | NRF24_stopListening(&spi_tx); 50 | NRF24_openWritingPipe(&spi_tx, pipeAddress); 51 | NRF24_setAutoAck(&spi_tx, true); 52 | NRF24_setChannel(&spi_tx, 52); 53 | NRF24_setPayloadSize(&spi_tx, 32); 54 | NRF24_enableDynamicPayloads(&spi_tx); 55 | NRF24_enableAckPayload(&spi_tx); 56 | 57 | while (1) { 58 | //**** TRANSMIT ****// 59 | if(NRF24_write(&spi_tx, myTxData, 32)){ 60 | NRF24_read(&spi_tx, AckPayload, 32); 61 | HAL_UART_Transmit(&huart2, (uint8_t *)"Transmitted Successfully\r\n", strlen("Transmitted Successfully\r\n"), 10); 62 | 63 | char myDataack[80]; 64 | sprintf(myDataack, "AckPayload: %s \r\n", AckPayload); 65 | HAL_UART_Transmit(&huart2, (uint8_t *)myDataack, strlen(myDataack), 10); 66 | } 67 | 68 | //**** RECEIVE ****// 69 | if(NRF24_available(&spi_rx)){ 70 | NRF24_read(&spi_rx, myRxData, 32); 71 | NRF24_writeAckPayload(&spi_rx, 1, myAckPayload, 32); 72 | myRxData[32] = '\r'; 73 | myRxData[32+1] = '\n'; 74 | HAL_UART_Transmit(&huart2, (uint8_t *)myRxData, 32+2, 10); 75 | } 76 | 77 | HAL_Delay(1000); // 1 second 78 | } 79 | 80 | ``` 81 | 82 | -------------------------------------------------------------------------------- /Optimized ILI9341 Touch LCD/Touch Screen/Frames/SAE J1939 Frames/SAE_J1939_Address_frame.c: -------------------------------------------------------------------------------- 1 | /* 2 | * SAE_J1939_Address_frame.c 3 | * 4 | * Created on: Jul 23, 2021 5 | * Author: Daniel Mårtensson 6 | */ 7 | 8 | #include "../../Touch_screen.h" 9 | #include "../../Hardware/ILI9341.h" 10 | #include "../../../Functions.h" 11 | 12 | void STM32_PLC_LCD_Show_SAE_J1939_Address_Frame(J1939 *j1939, uint8_t *frame_id) { 13 | /* Clear the screen , but not the icons */ 14 | ILI9341_fill_rect(51, 6, 314, 234, COLOR_NAVY); 15 | 16 | /* Write the title */ 17 | ILI9341_draw_horizontal_line(50, 30, 265, COLOR_GREEN); 18 | 19 | ILI9341_print_text("ECU address and connections", 55, 10, COLOR_YELLOW, COLOR_NAVY, 1); 20 | 21 | /* This ECU address */ 22 | char text[50]; 23 | sprintf(text, "This ECU address:%i", j1939->this_ECU_address); 24 | ILI9341_print_text(text, 55, 35, COLOR_YELLOW, COLOR_NAVY, 1); 25 | 26 | /* How many ECU are connected */ 27 | sprintf(text, "Other ECU connected:%i", j1939->number_of_ECU); 28 | ILI9341_print_text(text, 55, 45, COLOR_YELLOW, COLOR_NAVY, 1); 29 | 30 | /* Which ECU are connected */ 31 | sprintf(text, "Other ECU addresses:"); 32 | ILI9341_print_text(text, 55, 55, COLOR_YELLOW, COLOR_NAVY, 1); 33 | for(uint8_t i = 0; i < j1939->number_of_ECU; i++){ 34 | sprintf(text, "%i,", j1939->ECU_address[i]); 35 | ILI9341_print_text(text, 55 + i*10, 65, COLOR_YELLOW, COLOR_NAVY, 1); 36 | } 37 | 38 | /* How many ECU are not connected */ 39 | sprintf(text, "Other ECU not connected:%i", j1939->number_of_cannot_claim_address); 40 | ILI9341_print_text(text, 55, 75, COLOR_YELLOW, COLOR_NAVY, 1); 41 | 42 | /* Button */ 43 | ILI9341_fill_rect(65, 195, 300, 220, COLOR_GREEN); 44 | ILI9341_hollow_rect(65, 195, 300, 220, COLOR_BLACK); 45 | ILI9341_print_text("Set the ECU address", 70, 200, COLOR_BLACK, COLOR_GREEN, 2); 46 | 47 | /* Logic for button */ 48 | STM32_PLC_LCD_Call_One_Button_Logic(65, 195, 300, 220); 49 | 50 | /* Ask the user if */ 51 | if(STM32_PLC_LCD_Show_Question_Yes_No_Dialog("Do you want to set the ECU address?") == 0) { 52 | STM32_PLC_LCD_Show_Main_Frame(frame_id, false); 53 | return; 54 | } 55 | 56 | /* Enter a number */ 57 | float number_value; 58 | bool decimalbutton_show = false; 59 | bool minusbutton_show = false; 60 | if(STM32_PLC_LCD_Show_Numpad_Frame(decimalbutton_show, minusbutton_show, &number_value, "Enter address between 0 and 253") == 0) { 61 | STM32_PLC_LCD_Show_Main_Frame(frame_id, false); 62 | return; 63 | } 64 | uint8_t address; 65 | if(number_value < 0) 66 | address = 0; 67 | else if(number_value > 253) 68 | address = 253; 69 | else 70 | address = (uint8_t) number_value; 71 | 72 | /* Apply it */ 73 | j1939->this_ECU_address = address; 74 | 75 | /* Save it to SD card */ 76 | if(STM32_PLC_SD_Mont_Card() != FR_OK){ 77 | STM32_PLC_LCD_Show_Information_OK_Dialog("Could not mount SD card"); 78 | STM32_PLC_LCD_Show_Main_Frame(frame_id, false); 79 | return; 80 | } 81 | STM32_PLC_SD_Open_Existing_File_With_Write("ADDRESS.TXT"); 82 | sprintf(text, "%i", address); 83 | STM32_PLC_SD_Write_File(text); 84 | STM32_PLC_SD_Close_File(); 85 | STM32_PLC_SD_Unmount_Card(); 86 | 87 | /* Done */ 88 | STM32_PLC_LCD_Show_Main_Frame(frame_id, false); 89 | } 90 | -------------------------------------------------------------------------------- /FlashMemory_F3/ReadWrite.c: -------------------------------------------------------------------------------- 1 | /* 2 | * ReadWrite.c 3 | * 4 | * Created on: Dec 10, 2020 5 | * Author: Daniel Mårtensson 6 | */ 7 | 8 | #include "../FlashMemory_F3/ReadWrite.h" 9 | 10 | //Private variables 11 | //1. sector start address 12 | static uint32_t memory_address; 13 | 14 | // Set memory address 15 | void FlashSetAddrs(uint32_t address) { 16 | memory_address = address; 17 | } 18 | 19 | // Write Flash 20 | void FlashWriteN(uint32_t idx, void *wrBuf, uint32_t Nsize, DataTypeDef dataType) { 21 | uint32_t flashAddress = memory_address + idx; 22 | 23 | // Converter 24 | Convert convert; 25 | uint32_t wrBuf2[1]; 26 | 27 | //Unlock Flash 28 | HAL_FLASH_Unlock(); 29 | //Write to Flash 30 | switch (dataType) { 31 | case DATA_TYPE_U64: 32 | for (uint32_t i = 0; i < Nsize; i++) { 33 | HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, flashAddress, ((uint64_t*) wrBuf)[i]); 34 | flashAddress += 8; 35 | } 36 | break; 37 | 38 | case DATA_TYPE_U16: 39 | for (uint32_t i = 0; i < Nsize; i++) { 40 | HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, flashAddress, ((uint16_t*) wrBuf)[i]); 41 | flashAddress += 2; 42 | } 43 | break; 44 | 45 | case DATA_TYPE_U32: 46 | for (uint32_t i = 0; i < Nsize; i++) { 47 | HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, flashAddress, ((uint32_t*) wrBuf)[i]); 48 | flashAddress += 4; 49 | } 50 | break; 51 | 52 | case DATA_TYPE_FLOAT: 53 | for (uint32_t i = 0; i < Nsize; i++) { 54 | // Convert float -> uint8_t 55 | convert.float_value = ((float*) wrBuf)[i]; 56 | // Turn it to uint32_t 57 | wrBuf2[0] = convert.uint8_values[0] << 24 | convert.uint8_values[1] << 16 | convert.uint8_values[2] << 8 || convert.uint8_values[3]; 58 | // Write the uint32_t byte 59 | FlashWriteN(idx + 4*i, wrBuf2, 1, DATA_TYPE_U32); 60 | } 61 | break; 62 | } 63 | //Lock the Flash space 64 | HAL_FLASH_Lock(); 65 | } 66 | //4. Read Flash 67 | void FlashReadN(uint32_t idx, void *rdBuf, uint32_t Nsize, DataTypeDef dataType) { 68 | uint32_t flashAddress = memory_address + idx; 69 | 70 | // Converter 71 | Convert convert; 72 | uint32_t rdBuf2[1]; 73 | 74 | switch (dataType) { 75 | case DATA_TYPE_U64: 76 | for (uint32_t i = 0; i < Nsize; i++) { 77 | *((uint64_t*) rdBuf + i) = *(uint64_t*) flashAddress; 78 | flashAddress += 8; 79 | } 80 | break; 81 | 82 | case DATA_TYPE_U16: 83 | for (uint32_t i = 0; i < Nsize; i++) { 84 | *((uint16_t*) rdBuf + i) = *(uint16_t*) flashAddress; 85 | flashAddress += 2; 86 | } 87 | break; 88 | 89 | case DATA_TYPE_U32: 90 | for (uint32_t i = 0; i < Nsize; i++) { 91 | *((uint32_t*) rdBuf + i) = *(uint32_t*) flashAddress; 92 | flashAddress += 4; 93 | } 94 | break; 95 | 96 | case DATA_TYPE_FLOAT: 97 | for (uint32_t i = 0; i < Nsize; i++) { 98 | // Read the uint32_t byte 99 | FlashReadN(idx + 4 * i, rdBuf2, 1, DATA_TYPE_U32); 100 | // Convert uint32_t -> float 101 | convert.uint8_values[0] = rdBuf2[0] >> 24; 102 | convert.uint8_values[1] = rdBuf2[1] >> 16; 103 | convert.uint8_values[2] = rdBuf2[2] >> 8; 104 | convert.uint8_values[3] = rdBuf2[3]; 105 | *((float*) rdBuf + i) = convert.float_value; 106 | } 107 | break; 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /Optimized ILI9341 Touch LCD/Touch Screen/Logics/Main_logic.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Main_Logic.c 3 | * 4 | * Created on: Jul 23, 2021 5 | * Author: Daniel Mårtensson 6 | */ 7 | 8 | #include "../Touch_screen.h" 9 | #include "../Hardware/ILI9341.h" 10 | 11 | void STM32_PLC_LCD_Call_Main_Logic(uint8_t *frame_id, J1939 *j1939) { 12 | if (TSC2046_isPressed()) { 13 | TSC2046_GetTouchData(); 14 | uint16_t X = lcd.myTsData.X; 15 | uint16_t Y = lcd.myTsData.Y; 16 | /* Check which button we are pressing on */ 17 | if (X >= 8 && X <= 37 && Y >= 8 && Y <= 37) { /* First icon */ 18 | switch (*frame_id) { 19 | case 0: 20 | STM32_PLC_LCD_Show_Measurement_And_Time_Frame(frame_id); 21 | break; 22 | case 1: 23 | STM32_PLC_LCD_Show_Logging_Frame(j1939, frame_id); 24 | break; 25 | case 2: 26 | STM32_PLC_LCD_Show_SAE_J1939_Request_Frame(j1939, frame_id); 27 | break; 28 | case 3: 29 | STM32_PLC_LCD_Show_SAE_J1939_This_ECU_DM1_Frame(j1939, frame_id); 30 | break; 31 | case 4: 32 | STM32_PLC_LCD_Show_SAE_J1939_Other_ECU_DM2_Frame(j1939, frame_id); 33 | break; 34 | case 5: 35 | STM32_PLC_LCD_Show_SAE_J1939_This_ECU_Identifications_Frame(j1939, frame_id); 36 | break; 37 | case 6: 38 | STM32_PLC_LCD_Show_SDADC_Settings_Frame(frame_id); 39 | break; 40 | } 41 | } else if (X >= 8 && X <= 37 && Y >= 55 && Y <= 94) { /* Second icon */ 42 | switch (*frame_id) { 43 | case 0: 44 | STM32_PLC_LCD_Show_Analog_Calibration_Frame(frame_id); 45 | break; 46 | case 1: 47 | STM32_PLC_LCD_Show_Control_Program_Settings_Frame(frame_id); 48 | break; 49 | case 2: 50 | STM32_PLC_LCD_Show_SAE_J1939_Address_Frame(j1939, frame_id); 51 | break; 52 | case 3: 53 | STM32_PLC_LCD_Show_SAE_J1939_Other_ECU_DM1_Frame(j1939, frame_id); 54 | break; 55 | case 4: 56 | STM32_PLC_LCD_Show_SAE_J1939_This_ECU_Name_Frame(j1939, frame_id); 57 | break; 58 | case 5: 59 | STM32_PLC_LCD_Show_SAE_J1939_Other_ECU_Identifications_Frame(j1939, frame_id); 60 | break; 61 | } 62 | } else if (X >= 8 && X <= 37 && Y >= 100 && Y <= 139) { /* Third icon */ 63 | switch (*frame_id) { 64 | case 0: 65 | STM32_PLC_LCD_Show_PWM_Frequency_Settings_Frame(frame_id); 66 | break; 67 | case 1: 68 | STM32_PLC_LCD_Show_Date_Time_Alarm_Settings_Frame(frame_id); 69 | break; 70 | case 2: 71 | STM32_PLC_LCD_Show_SAE_J1939_Commanded_Address_Frame(j1939, frame_id); 72 | break; 73 | case 3: 74 | STM32_PLC_LCD_Show_SAE_J1939_This_ECU_DM2_Frame(j1939, frame_id); 75 | break; 76 | case 4: 77 | STM32_PLC_LCD_Show_SAE_J1939_Other_ECU_Name_Frame(j1939, frame_id); 78 | break; 79 | case 5: 80 | STM32_PLC_LCD_Show_Encoder_Revolutions_Settings_Frame(frame_id); 81 | break; 82 | } 83 | } else if (X >= 8 && X <= 37 && Y >= 146 && Y <= 185) { /* Fourth icon */ 84 | if (*frame_id > 0) { 85 | *frame_id = *frame_id - 1; /* Got to previous frame */ 86 | STM32_PLC_LCD_Show_Main_Frame(frame_id, true); 87 | } 88 | } else if (X >= 8 && X <= 37 && Y >= 193 && Y <= 232) { /* Fifth icon */ 89 | if (*frame_id < 7) { 90 | *frame_id = *frame_id + 1; /* Go to next frame */ 91 | STM32_PLC_LCD_Show_Main_Frame(frame_id, true); 92 | } 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /Optimized ILI9341 Touch LCD/Touch Screen/Logics/Numpad_logic.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Numpad_frame.c 3 | * 4 | * Created on: Jul 23, 2021 5 | * Author: Daniel Mårtensson 6 | */ 7 | 8 | #include "../Touch_screen.h" 9 | #include "../Hardware/ILI9341.h" 10 | 11 | uint8_t STM32_PLC_LCD_Call_Numpad_Logic(bool decimalbutton_show, bool minusbutton_show, float *number_value) { 12 | bool haveDot = false; 13 | char text[17] = ""; 14 | uint8_t k = 0; 15 | while (1) { 16 | if (TSC2046_isPressed()) { 17 | TSC2046_GetTouchData(); 18 | uint16_t X = lcd.myTsData.X; 19 | uint16_t Y = lcd.myTsData.Y; 20 | if (X >= 23 && X <= 63 && Y >= 70 && Y <= 110) { 21 | /* 0 */ 22 | if (k >= 0 && k < 16) { 23 | text[k] = '0'; 24 | k++; 25 | } 26 | } else if (X >= 81 && X <= 121 && Y >= 70 && Y <= 110) { 27 | /* 1 */ 28 | if (k < 16) { 29 | text[k] = '1'; 30 | k++; 31 | } 32 | } else if (X >= 139 && X <= 179 && Y >= 70 && Y <= 110) { 33 | /* 2 */ 34 | if (k < 16) { 35 | text[k] = '2'; 36 | k++; 37 | } 38 | } else if (X >= 197 && X <= 237 && Y >= 70 && Y <= 110) { 39 | /* 3 */ 40 | if (k < 16) { 41 | text[k] = '3'; 42 | k++; 43 | } 44 | } else if (X >= 255 && X <= 295 && Y >= 70 && Y <= 110) { 45 | /* 4 */ 46 | if (k < 16) { 47 | text[k] = '4'; 48 | k++; 49 | } 50 | } else if (X >= 23 && X <= 63 && Y >= 125 && Y <= 165) { 51 | /* 5 */ 52 | if (k < 16) { 53 | text[k] = '5'; 54 | k++; 55 | } 56 | } else if (X >= 81 && X <= 121 && Y >= 125 && Y <= 165) { 57 | /* 6 */ 58 | if (k < 16) { 59 | text[k] = '6'; 60 | k++; 61 | } 62 | } else if (X >= 139 && X <= 179 && Y >= 125 && Y <= 165) { 63 | /* 7 */ 64 | if (k < 16) { 65 | text[k] = '7'; 66 | k++; 67 | } 68 | } else if (X >= 197 && X <= 237 && Y >= 125 && Y <= 165) { 69 | /* 8 */ 70 | if (k < 16) { 71 | text[k] = '8'; 72 | k++; 73 | } 74 | } else if (X >= 255 && X <= 295 && Y >= 125 && Y <= 165) { 75 | /* 9 */ 76 | if (k < 16) { 77 | text[k] = '9'; 78 | k++; 79 | } 80 | } else if (X >= 23 && X <= 63 && Y >= 180 && Y <= 220) { 81 | /* - */ 82 | if (minusbutton_show == true && k == 0) { 83 | text[k] = '-'; 84 | k++; 85 | } 86 | } else if (X >= 81 && X <= 121 && Y >= 180 && Y <= 220) { 87 | /* . */ 88 | if (decimalbutton_show == true && k > 0 && haveDot == false && k < 16) { 89 | text[k] = '.'; 90 | k++; 91 | haveDot = true; 92 | } 93 | } else if (X >= 139 && X <= 179 && Y >= 180 && Y <= 220) { 94 | /* C */ 95 | memset(text, 0, sizeof(text)); 96 | k = 0; 97 | haveDot = false; 98 | ILI9341_fill_rect(12, 24, 308, 50, COLOR_WHITE); /* Clear white space above */ 99 | } else if (X >= 197 && X <= 237 && Y >= 180 && Y <= 220) { 100 | /* <- */ 101 | return 0; 102 | } else if (X >= 255 && X <= 295 && Y >= 180 && Y <= 220) { 103 | /* OK */ 104 | *number_value = atoff(text); 105 | return 1; 106 | } 107 | /* Display the selected number text */ 108 | ILI9341_print_text(text, 15, 25, COLOR_BLACK, COLOR_WHITE, 3); 109 | } 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /VL6180X/VL6180X.h: -------------------------------------------------------------------------------- 1 | /* 2 | * VL6180X.h 3 | * 4 | * Created on: Jun 23, 2021 5 | * Author: Daniel Mårtensson 6 | */ 7 | 8 | #include "main.h" 9 | #include "stdbool.h" 10 | 11 | #ifndef SRC_VL6180X_VL6180X_H_ 12 | #define SRC_VL6180X_VL6180X_H_ 13 | 14 | #define VL6180X_DEFAULT_I2C_ADDR 0x52 // (0x29 < 1) - The fixed I2C addres 15 | ///! Device model identification number 16 | #define VL6180X_REG_IDENTIFICATION_MODEL_ID 0x000 17 | ///! Interrupt configuration 18 | #define VL6180X_REG_SYSTEM_INTERRUPT_CONFIG 0x014 19 | ///! Interrupt clear bits 20 | #define VL6180X_REG_SYSTEM_INTERRUPT_CLEAR 0x015 21 | ///! Fresh out of reset bit 22 | #define VL6180X_REG_SYSTEM_FRESH_OUT_OF_RESET 0x016 23 | ///! Trigger Ranging 24 | #define VL6180X_REG_SYSRANGE_START 0x018 25 | ///! Trigger Lux Reading 26 | #define VL6180X_REG_SYSALS_START 0x038 27 | ///! Lux reading gain 28 | #define VL6180X_REG_SYSALS_ANALOGUE_GAIN 0x03F 29 | ///! Integration period for ALS mode, high byte 30 | #define VL6180X_REG_SYSALS_INTEGRATION_PERIOD_HI 0x040 31 | ///! Integration period for ALS mode, low byte 32 | #define VL6180X_REG_SYSALS_INTEGRATION_PERIOD_LO 0x041 33 | ///! Specific error codes 34 | #define VL6180X_REG_RESULT_RANGE_STATUS 0x04d 35 | ///! Interrupt status 36 | #define VL6180X_REG_RESULT_INTERRUPT_STATUS_GPIO 0x04f 37 | ///! Light reading value 38 | #define VL6180X_REG_RESULT_ALS_VAL 0x050 39 | ///! Ranging reading value 40 | #define VL6180X_REG_RESULT_RANGE_VAL 0x062 41 | ///! I2C Slave Device Address 42 | #define VL6180X_REG_SLAVE_DEVICE_ADDRESS 0x212 43 | 44 | #define VL6180X_ALS_GAIN_1 0x06 ///< 1x gain 45 | #define VL6180X_ALS_GAIN_1_25 0x05 ///< 1.25x gain 46 | #define VL6180X_ALS_GAIN_1_67 0x04 ///< 1.67x gain 47 | #define VL6180X_ALS_GAIN_2_5 0x03 ///< 2.5x gain 48 | #define VL6180X_ALS_GAIN_5 0x02 ///< 5x gain 49 | #define VL6180X_ALS_GAIN_10 0x01 ///< 10x gain 50 | #define VL6180X_ALS_GAIN_20 0x00 ///< 20x gain 51 | #define VL6180X_ALS_GAIN_40 0x07 ///< 40x gain 52 | 53 | #define VL6180X_ERROR_NONE 0 ///< Success! 54 | #define VL6180X_ERROR_SYSERR_1 1 ///< System error 55 | #define VL6180X_ERROR_SYSERR_5 5 ///< Sysem error 56 | #define VL6180X_ERROR_ECEFAIL 6 ///< Early convergence estimate fail 57 | #define VL6180X_ERROR_NOCONVERGE 7 ///< No target detected 58 | #define VL6180X_ERROR_RANGEIGNORE 8 ///< Ignore threshold check failed 59 | #define VL6180X_ERROR_SNR 11 ///< Ambient conditions too high 60 | #define VL6180X_ERROR_RAWUFLOW 12 ///< Raw range algo underflow 61 | #define VL6180X_ERROR_RAWOFLOW 13 ///< Raw range algo overflow 62 | #define VL6180X_ERROR_RANGEUFLOW 14 ///< Raw range algo underflow 63 | #define VL6180X_ERROR_RANGEOFLOW 15 ///< Raw range algo overflow 64 | 65 | 66 | bool VL6180X_Init(I2C_HandleTypeDef *hi2c); 67 | bool VL6180X_setAddress(uint8_t newAddr); 68 | uint8_t VL6180X_getAddress(void); 69 | 70 | uint8_t VL6180X_readRange(void); 71 | float VL6180X_readLux(uint8_t gain); 72 | uint8_t VL6180X_readRangeStatus(void); 73 | 74 | bool VL6180X_startRange(void); 75 | bool VL6180X_isRangeComplete(void); 76 | bool VL6180X_waitRangeComplete(void); 77 | uint8_t VL6180X_readRangeResult(void); 78 | 79 | void VL6180X_startRangeContinuous(uint16_t period_ms); 80 | void VL6180X_stopRangeContinuous(void); 81 | 82 | 83 | #endif /* SRC_VL6180X_VL6180X_H_ */ 84 | -------------------------------------------------------------------------------- /ADXL345/ReadMe.md: -------------------------------------------------------------------------------- 1 | # ADXL345 Accelerometer 10-Bit 2 | This is an accelerometer, named ADXL345. With this you can measure the acceleration i x, y and 3 | z-axis with resolution 10-bit. ADXL345 have both I2C and SPI communication. 4 | 5 | Program example: 6 | 7 | ``` 8 | // Include 9 | #include "ADXL345/ADXL345.h" 10 | 11 | // Structure 12 | SPI_HandleTypeDef hspi3; 13 | ADXL345_SPI_I2C adxl; 14 | 15 | // Init - Select ONE option 16 | ADXL345_I2C(&adxl, &hi2c1, 0x53); // Declare object with address - I2C 17 | ADXL345_SPI(&adxl, &hspi3, GPIOA, GPIO_PIN_8); // Declare object with CS - SPI 18 | 19 | // Start up 20 | ADXL345powerOn(&adxl); // Power on the ADXL345 21 | 22 | ADXL345setRangeSetting(&adxl, 16); // Give the range settings 23 | // Accepted values are 2g, 4g, 8g or 16g 24 | // Higher Values = Wider Measurement Range 25 | // Lower Values = Greater Sensitivity 26 | 27 | ADXL345setSpiBit(&adxl, 0); // Configure the device to be in 4 wire SPI mode when set to '0' or 3 wire SPI mode when set to 1 28 | // Default: Set to 1 29 | // SPI pins on the ATMega328: 11, 12 and 13 as reference in SPI Library 30 | 31 | ADXL345setActivityXYZ(&adxl, 1, 0, 0); // Set to activate movement detection in the axes "adxl.setActivityXYZ(X, Y, Z);" (1 == ON, 0 == OFF) 32 | ADXL345setActivityThreshold(&adxl, 75); // 62.5mg per increment // Set activity // Inactivity thresholds (0-255) 33 | 34 | ADXL345setInactivityXYZ(&adxl, 1, 0, 0); // Set to detect inactivity in all the axes "adxl.setInactivityXYZ(X, Y, Z);" (1 == ON, 0 == OFF) 35 | ADXL345setInactivityThreshold(&adxl, 75); // 62.5mg per increment // Set inactivity // Inactivity thresholds (0-255) 36 | ADXL345setTimeInactivity(&adxl, 10); // How many seconds of no activity is inactive? 37 | 38 | ADXL345setTapDetectionOnXYZ(&adxl, 0, 0, 1); // Detect taps in the directions turned ON "adxl.setTapDetectionOnX(X, Y, Z);" (1 == ON, 0 == OFF) 39 | 40 | // Set values for what is considered a TAP and what is a DOUBLE TAP (0-255) 41 | ADXL345setTapThreshold(&adxl, 50); // 62.5 mg per increment 42 | ADXL345setTapDuration(&adxl, 15); // 625 μs per increment 43 | ADXL345setDoubleTapLatency(&adxl, 80); // 1.25 ms per increment 44 | ADXL345setDoubleTapWindow(&adxl, 200); // 1.25 ms per increment 45 | 46 | // Set values for what is considered FREE FALL (0-255) 47 | ADXL345setFreeFallThreshold(&adxl, 7); // (5 - 9) recommended - 62.5mg per increment 48 | ADXL345setFreeFallDuration(&adxl, 30); // (20 - 70) recommended - 5ms per increment 49 | 50 | ADXL345InactivityINT(&adxl, 1); 51 | ADXL345ActivityINT(&adxl, 1); 52 | ADXL345FreeFallINT(&adxl, 1); 53 | ADXL345doubleTapINT(&adxl, 1); 54 | ADXL345singleTapINT(&adxl, 1); 55 | 56 | while(1){ 57 | // Read the accelerometer values and store them in variables declared above x,y,z 58 | int x,y,z; 59 | ADXL345readAccel_x_y_z(&adxl, &x, &y, &z); 60 | 61 | } 62 | -------------------------------------------------------------------------------- /MAX31865/MAX31865.c: -------------------------------------------------------------------------------- 1 | 2 | #include "MAX31865.h" 3 | 4 | /* 5 | * Write to 6 | */ 7 | static void MAX31865_write(MAX31865_SPI* spi, uint8_t* address, uint8_t* data, uint16_t lenght) { 8 | 9 | // Enable CE 10 | HAL_GPIO_WritePin(spi->CE_PORT, spi->CE_PIN, GPIO_PIN_RESET); 11 | HAL_SPI_Transmit(spi->hspi, address, 1, 10); 12 | HAL_SPI_Transmit(spi->hspi, data, lenght, 10); 13 | // Disable CE 14 | HAL_GPIO_WritePin(spi->CE_PORT, spi->CE_PIN, GPIO_PIN_SET); 15 | } 16 | 17 | /* 18 | * Read from 19 | */ 20 | static void MAX31865_read(MAX31865_SPI* spi, uint8_t* address, uint8_t* buffer, uint16_t lenght) { 21 | 22 | // Enable CE 23 | HAL_GPIO_WritePin(spi->CE_PORT, spi->CE_PIN, GPIO_PIN_RESET); 24 | HAL_SPI_Transmit(spi->hspi, address, 1, 10); 25 | HAL_SPI_Receive(spi->hspi, buffer, lenght, 10); 26 | // Disable CE 27 | HAL_GPIO_WritePin(spi->CE_PORT, spi->CE_PIN, GPIO_PIN_SET); 28 | 29 | } 30 | 31 | /* 32 | * Read temperature 33 | */ 34 | float MAX31865_temperature(MAX31865_SPI* spi) { 35 | 36 | uint8_t buffer[2]; 37 | uint8_t address = 0x01; // MAX31865_RTD_MSB 38 | MAX31865_read(spi, &address, buffer, 2); 39 | 40 | // Combine 2 bytes into 1 number, and shift 1 down to remove fault bit 41 | uint16_t data = buffer[0] << 8; 42 | data |= buffer[1]; 43 | data >>= 1; 44 | 45 | // Calculate the actual resistance of the sensor 46 | float resistance = ((float) data * MAX31865_RREF) / MAX31865_FACTOR; 47 | 48 | // Calculate the temperature from the measured resistance 49 | float temp = ((resistance / 100) - 1) / MAX31865_ALPHA; 50 | 51 | return temp; 52 | 53 | } 54 | 55 | /* 56 | * Get the raw resistance 57 | */ 58 | uint16_t MAX31865_raw_resistance(MAX31865_SPI* spi){ 59 | uint8_t buffer[2]; 60 | uint8_t address = 0x01; // MAX31865_RTD_MSB 61 | MAX31865_read(spi, &address, buffer, 2); 62 | 63 | // Combine 2 bytes into 1 number, and shift 1 down to remove fault bit 64 | uint16_t data = buffer[0] << 8; 65 | data |= buffer[1]; 66 | data >>= 1; 67 | return data; 68 | } 69 | 70 | /* 71 | * Get the configuration 72 | */ 73 | uint8_t MAX31865_configuration(MAX31865_SPI* spi){ 74 | uint8_t address = 0x00; // MAX31865_CONFIGURATION 75 | uint8_t buffer; 76 | MAX31865_read(spi, &address, &buffer, 1); 77 | return buffer; 78 | } 79 | 80 | void MAX31865_init(MAX31865_SPI* spi, GPIO_TypeDef* CE_PORT, uint16_t CE_PIN, SPI_HandleTypeDef* hspi, uint8_t WIRES){ 81 | // Declare structure 82 | spi->CE_PIN = CE_PIN; 83 | spi->CE_PORT = CE_PORT; 84 | spi->hspi = hspi; 85 | spi->WIRES = WIRES; 86 | 87 | // CE in reset state 88 | HAL_GPIO_WritePin(spi->CE_PORT, spi->CE_PIN, GPIO_PIN_SET); 89 | 90 | /* 91 | * SPI settings: 92 | * CPHA = 2 Edge 93 | * Prescaler = 256 94 | * First bit = MBS first 95 | * CPOL = High 96 | */ 97 | 98 | // Do default configuration and begin with creating the data 99 | /* 100 | * VBias = ON 101 | * Conversion mode = Auto 102 | * 1-shot = Off 103 | * Fault detection = No action 104 | * Fault Status = Off 105 | * Filter = 60 Hz 106 | */ 107 | uint8_t data = 0x00; 108 | if (spi->WIRES == WIRE3) { 109 | data = 0b11010000; // 3 wire 110 | } else { 111 | data = 0b11000000; // 2 or 4 wire 112 | } 113 | 114 | // 0x80 will convert to WRITE address 115 | uint8_t address = 0x00 | 0x80; // MAX31865_CONFIGURATION 116 | MAX31865_write(spi, &address, &data, 1); 117 | 118 | 119 | } 120 | -------------------------------------------------------------------------------- /HX711 Load Cell Amplifier/HX711.h: -------------------------------------------------------------------------------- 1 | /* 2 | * HX711.h 3 | * 4 | * Created on: Jun 6, 2020 5 | * Author: Daniel Mårtensson 6 | */ 7 | 8 | #ifndef SRC_HX711_HX711_H_ 9 | #define SRC_HX711_HX711_H_ 10 | 11 | #include "main.h" 12 | #include "stdbool.h" 13 | 14 | #define SMALL_DELAY 10 15 | #define LSBFIRST 0 16 | #define MSBFIRST 1 17 | typedef struct { 18 | // Power Down and Serial Clock Input Pin - This must be output! 19 | GPIO_TypeDef *PD_SCK_Port; 20 | uint16_t PD_SCK_Pin; 21 | 22 | // Serial Data Output Pin - This must be pull-up! 23 | GPIO_TypeDef *DOUT_Port; 24 | uint16_t DOUT_Pin; 25 | 26 | uint8_t GAIN; // amplification factor 27 | long OFFSET; // used for tare weight 28 | float SCALE; // used to return weight in grams, kg, ounces, whatever 29 | } HX711; 30 | 31 | // Initialize library with data output pin, clock input pin and gain factor. 32 | // Channel selection is made by passing the appropriate gain: 33 | // - With a gain factor of 64 or 128, channel A is selected 34 | // - With a gain factor of 32, channel B is selected 35 | // The library default is "128" (Channel A). 36 | void HX711_begin(HX711 *hx, GPIO_TypeDef* PD_SCK_Port, uint16_t PD_SCK_Pin, GPIO_TypeDef* DOUT_Port, uint16_t DOUT_Pin, uint8_t gain); 37 | 38 | // Check if HX711 is ready 39 | // from the datasheet: When output data is not ready for retrieval, digital output pin DOUT is high. Serial clock 40 | // input PD_SCK should be low. When DOUT goes to low, it indicates data is ready for retrieval. 41 | bool HX711_is_ready(HX711 *hx); 42 | 43 | // Wait for the HX711 to become ready 44 | void HX711_wait_ready(HX711 *hx, unsigned long delay_ms); 45 | bool HX711_wait_ready_retry(HX711 *hx, int retries, unsigned long delay_ms); 46 | bool HX711_wait_ready_timeout(HX711 *hx, unsigned long timeout, unsigned long delay_ms); 47 | 48 | // set the gain factor; takes effect only after a call to read() 49 | // channel A can be set for a 128 or 64 gain; channel B has a fixed 32 gain 50 | // depending on the parameter, the channel is also set to either A or B 51 | void HX711_set_gain(HX711 *hx, uint8_t gain); 52 | 53 | // waits for the chip to be ready and returns a reading 54 | long HX711_read(HX711 *hx); 55 | 56 | // returns an average reading; times = how many times to read 57 | long HX711_read_average(HX711 *hx, uint8_t times); 58 | 59 | // returns (read_average() - OFFSET), that is the current value without the tare weight; times = how many readings to do 60 | float HX711_get_value(HX711 *hx, uint8_t times); 61 | 62 | // returns get_value() divided by SCALE, that is the raw value divided by a value obtained via calibration 63 | // times = how many readings to do 64 | float HX711_get_units(HX711 *hx, uint8_t times); 65 | 66 | // set the OFFSET value for tare weight; times = how many times to read the tare value 67 | void HX711_tare(HX711 *hx, uint8_t times); 68 | 69 | // set the SCALE value; this value is used to convert the raw data to "human readable" data (measure units) 70 | void HX711_set_scale(HX711 *hx, float scale); 71 | 72 | // get the current SCALE 73 | float HX711_get_scale(HX711 *hx); 74 | 75 | // set OFFSET, the value that's subtracted from the actual reading (tare weight) 76 | void HX711_set_offset(HX711 *hx, long offset); 77 | 78 | // get the current OFFSET 79 | long HX711_get_offset(HX711 *hx); 80 | 81 | // puts the chip into power down mode 82 | void HX711_power_down(HX711 *hx); 83 | 84 | // wakes up the chip after power down mode 85 | void HX711_power_up(HX711 *hx); 86 | 87 | #endif /* SRC_HX711_HX711_H_ */ 88 | -------------------------------------------------------------------------------- /FlashMemory/ReadWrite.c: -------------------------------------------------------------------------------- 1 | /* 2 | * ReadWrite.c 3 | * 4 | * Created on: Jul 5, 2020 5 | * Author: Daniel Mårtensson 6 | */ 7 | 8 | #include "ReadWrite.h" 9 | 10 | //Private variables 11 | //1. sector start address 12 | static uint32_t SectorAddrs; 13 | static uint8_t SectorNum; 14 | 15 | //functions definitions 16 | //1. Erase Sector 17 | void FlashEraseSector() { 18 | HAL_FLASH_Unlock(); 19 | //Erase the required Flash sector 20 | FLASH_Erase_Sector(SectorNum, FLASH_VOLTAGE_RANGE_3); 21 | HAL_FLASH_Lock(); 22 | } 23 | 24 | //2. Set Sector Adress 25 | void FlashSetSectorAddrs(uint8_t sector, uint32_t addrs) { 26 | SectorNum = sector; 27 | SectorAddrs = addrs; 28 | } 29 | 30 | //3. Write Flash 31 | void FlashWriteN(uint32_t idx, void *wrBuf, uint32_t Nsize, DataTypeDef dataType) { 32 | uint32_t flashAddress = SectorAddrs + idx; 33 | 34 | // Converter 35 | Convert convert; 36 | uint8_t wrBuf2[4]; 37 | 38 | //Unlock Flash 39 | HAL_FLASH_Unlock(); 40 | //Write to Flash 41 | switch (dataType) { 42 | case DATA_TYPE_U8: 43 | for (uint32_t i = 0; i < Nsize; i++) { 44 | HAL_FLASH_Program(FLASH_TYPEPROGRAM_BYTE, flashAddress, ((uint8_t*) wrBuf)[i]); 45 | flashAddress++; 46 | } 47 | break; 48 | 49 | case DATA_TYPE_U16: 50 | for (uint32_t i = 0; i < Nsize; i++) { 51 | HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, flashAddress, ((uint16_t*) wrBuf)[i]); 52 | flashAddress += 2; 53 | } 54 | break; 55 | 56 | case DATA_TYPE_U32: 57 | for (uint32_t i = 0; i < Nsize; i++) { 58 | HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, flashAddress, ((uint32_t*) wrBuf)[i]); 59 | flashAddress += 4; 60 | } 61 | break; 62 | 63 | case DATA_TYPE_FLOAT: 64 | for (uint32_t i = 0; i < Nsize; i++) { 65 | // Convert float -> uint8_t 66 | convert.float_value = ((float*) wrBuf)[i]; 67 | wrBuf2[0] = convert.uint8_values[0]; 68 | wrBuf2[1] = convert.uint8_values[1]; 69 | wrBuf2[2] = convert.uint8_values[2]; 70 | wrBuf2[3] = convert.uint8_values[3]; 71 | // Write the uint8_t bytes 72 | FlashWriteN(idx + 4*i, wrBuf2, 4, DATA_TYPE_U8); 73 | } 74 | break; 75 | } 76 | //Lock the Flash space 77 | HAL_FLASH_Lock(); 78 | } 79 | //4. Read Flash 80 | void FlashReadN(uint32_t idx, void *rdBuf, uint32_t Nsize, DataTypeDef dataType) { 81 | uint32_t flashAddress = SectorAddrs + idx; 82 | 83 | // Converter 84 | Convert convert; 85 | uint8_t rdBuf2[4]; 86 | 87 | switch (dataType) { 88 | case DATA_TYPE_U8: 89 | for (uint32_t i = 0; i < Nsize; i++) { 90 | *((uint8_t*) rdBuf + i) = *(uint8_t*) flashAddress; 91 | flashAddress++; 92 | } 93 | break; 94 | 95 | case DATA_TYPE_U16: 96 | for (uint32_t i = 0; i < Nsize; i++) { 97 | *((uint16_t*) rdBuf + i) = *(uint16_t*) flashAddress; 98 | flashAddress += 2; 99 | } 100 | break; 101 | 102 | case DATA_TYPE_U32: 103 | for (uint32_t i = 0; i < Nsize; i++) { 104 | *((uint32_t*) rdBuf + i) = *(uint32_t*) flashAddress; 105 | flashAddress += 4; 106 | } 107 | break; 108 | 109 | case DATA_TYPE_FLOAT: 110 | for (uint32_t i = 0; i < Nsize; i++) { 111 | // Read the uint8_t bytes 112 | FlashReadN(idx + 4*i, rdBuf2, 4, DATA_TYPE_U8); 113 | // Convert uint8_t -> float 114 | convert.uint8_values[0] = rdBuf2[0]; 115 | convert.uint8_values[1] = rdBuf2[1]; 116 | convert.uint8_values[2] = rdBuf2[2]; 117 | convert.uint8_values[3] = rdBuf2[3]; 118 | *((float*) rdBuf + i) = convert.float_value; 119 | } 120 | break; 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /FlashMemory_F4/ReadWrite.c: -------------------------------------------------------------------------------- 1 | /* 2 | * ReadWrite.c 3 | * 4 | * Created on: Jul 5, 2020 5 | * Author: Daniel Mårtensson 6 | */ 7 | 8 | #include "ReadWrite.h" 9 | 10 | //Private variables 11 | //1. sector start address 12 | static uint32_t SectorAddrs; 13 | static uint8_t SectorNum; 14 | 15 | //functions definitions 16 | //1. Erase Sector 17 | void FlashEraseSector() { 18 | HAL_FLASH_Unlock(); 19 | //Erase the required Flash sector 20 | FLASH_Erase_Sector(SectorNum, FLASH_VOLTAGE_RANGE_3); 21 | HAL_FLASH_Lock(); 22 | } 23 | 24 | //2. Set Sector Adress 25 | void FlashSetSectorAddrs(uint8_t sector, uint32_t addrs) { 26 | SectorNum = sector; 27 | SectorAddrs = addrs; 28 | } 29 | 30 | //3. Write Flash 31 | void FlashWriteN(uint32_t idx, void *wrBuf, uint32_t Nsize, DataTypeDef dataType) { 32 | uint32_t flashAddress = SectorAddrs + idx; 33 | 34 | // Converter 35 | Convert convert; 36 | uint8_t wrBuf2[4]; 37 | 38 | //Unlock Flash 39 | HAL_FLASH_Unlock(); 40 | //Write to Flash 41 | switch (dataType) { 42 | case DATA_TYPE_U8: 43 | for (uint32_t i = 0; i < Nsize; i++) { 44 | HAL_FLASH_Program(FLASH_TYPEPROGRAM_BYTE, flashAddress, ((uint8_t*) wrBuf)[i]); 45 | flashAddress++; 46 | } 47 | break; 48 | 49 | case DATA_TYPE_U16: 50 | for (uint32_t i = 0; i < Nsize; i++) { 51 | HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, flashAddress, ((uint16_t*) wrBuf)[i]); 52 | flashAddress += 2; 53 | } 54 | break; 55 | 56 | case DATA_TYPE_U32: 57 | for (uint32_t i = 0; i < Nsize; i++) { 58 | HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, flashAddress, ((uint32_t*) wrBuf)[i]); 59 | flashAddress += 4; 60 | } 61 | break; 62 | 63 | case DATA_TYPE_FLOAT: 64 | for (uint32_t i = 0; i < Nsize; i++) { 65 | // Convert float -> uint8_t 66 | convert.float_value = ((float*) wrBuf)[i]; 67 | wrBuf2[0] = convert.uint8_values[0]; 68 | wrBuf2[1] = convert.uint8_values[1]; 69 | wrBuf2[2] = convert.uint8_values[2]; 70 | wrBuf2[3] = convert.uint8_values[3]; 71 | // Write the uint8_t bytes 72 | FlashWriteN(idx + 4*i, wrBuf2, 4, DATA_TYPE_U8); 73 | } 74 | break; 75 | } 76 | //Lock the Flash space 77 | HAL_FLASH_Lock(); 78 | } 79 | //4. Read Flash 80 | void FlashReadN(uint32_t idx, void *rdBuf, uint32_t Nsize, DataTypeDef dataType) { 81 | uint32_t flashAddress = SectorAddrs + idx; 82 | 83 | // Converter 84 | Convert convert; 85 | uint8_t rdBuf2[4]; 86 | 87 | switch (dataType) { 88 | case DATA_TYPE_U8: 89 | for (uint32_t i = 0; i < Nsize; i++) { 90 | *((uint8_t*) rdBuf + i) = *(uint8_t*) flashAddress; 91 | flashAddress++; 92 | } 93 | break; 94 | 95 | case DATA_TYPE_U16: 96 | for (uint32_t i = 0; i < Nsize; i++) { 97 | *((uint16_t*) rdBuf + i) = *(uint16_t*) flashAddress; 98 | flashAddress += 2; 99 | } 100 | break; 101 | 102 | case DATA_TYPE_U32: 103 | for (uint32_t i = 0; i < Nsize; i++) { 104 | *((uint32_t*) rdBuf + i) = *(uint32_t*) flashAddress; 105 | flashAddress += 4; 106 | } 107 | break; 108 | 109 | case DATA_TYPE_FLOAT: 110 | for (uint32_t i = 0; i < Nsize; i++) { 111 | // Read the uint8_t bytes 112 | FlashReadN(idx + 4*i, rdBuf2, 4, DATA_TYPE_U8); 113 | // Convert uint8_t -> float 114 | convert.uint8_values[0] = rdBuf2[0]; 115 | convert.uint8_values[1] = rdBuf2[1]; 116 | convert.uint8_values[2] = rdBuf2[2]; 117 | convert.uint8_values[3] = rdBuf2[3]; 118 | *((float*) rdBuf + i) = convert.float_value; 119 | } 120 | break; 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /PCA9685 PWM Servo/PCA9685.h: -------------------------------------------------------------------------------- 1 | /* 2 | * PCA9685.h 3 | * 4 | * Created on: Jun 6, 2020 5 | * Author: Daniel Mårtensson 6 | */ 7 | 8 | #ifndef SRC_PCA9685_PWM_SERVO_PCA9685_H_ 9 | #define SRC_PCA9685_PWM_SERVO_PCA9685_H_ 10 | 11 | #include "main.h" 12 | #include "stdbool.h" 13 | 14 | // REGISTER ADDRESSES 15 | #define PCA9685_MODE1 0x00 /**< Mode Register 1 */ 16 | #define PCA9685_MODE2 0x01 /**< Mode Register 2 */ 17 | #define PCA9685_SUBADR1 0x02 /**< I2C-bus subaddress 1 */ 18 | #define PCA9685_SUBADR2 0x03 /**< I2C-bus subaddress 2 */ 19 | #define PCA9685_SUBADR3 0x04 /**< I2C-bus subaddress 3 */ 20 | #define PCA9685_ALLCALLADR 0x05 /**< LED All Call I2C-bus address */ 21 | #define PCA9685_LED0_ON_L 0x06 /**< LED0 on tick, low byte*/ 22 | #define PCA9685_LED0_ON_H 0x07 /**< LED0 on tick, high byte*/ 23 | #define PCA9685_LED0_OFF_L 0x08 /**< LED0 off tick, low byte */ 24 | #define PCA9685_LED0_OFF_H 0x09 /**< LED0 off tick, high byte */ 25 | // etc all 16: LED15_OFF_H 0x45 26 | #define PCA9685_ALLLED_ON_L 0xFA /**< load all the LEDn_ON registers, low */ 27 | #define PCA9685_ALLLED_ON_H 0xFB /**< load all the LEDn_ON registers, high */ 28 | #define PCA9685_ALLLED_OFF_L 0xFC /**< load all the LEDn_OFF registers, low */ 29 | #define PCA9685_ALLLED_OFF_H 0xFD /**< load all the LEDn_OFF registers,high */ 30 | #define PCA9685_PRESCALE 0xFE /**< Prescaler for PWM output frequency */ 31 | #define PCA9685_TESTMODE 0xFF /**< defines the test mode to be entered */ 32 | 33 | // MODE1 bits 34 | #define MODE1_ALLCAL 0x01 /**< respond to LED All Call I2C-bus address */ 35 | #define MODE1_SUB3 0x02 /**< respond to I2C-bus subaddress 3 */ 36 | #define MODE1_SUB2 0x04 /**< respond to I2C-bus subaddress 2 */ 37 | #define MODE1_SUB1 0x08 /**< respond to I2C-bus subaddress 1 */ 38 | #define MODE1_SLEEP 0x10 /**< Low power mode. Oscillator off */ 39 | #define MODE1_AI 0x20 /**< Auto-Increment enabled */ 40 | #define MODE1_EXTCLK 0x40 /**< Use EXTCLK pin clock */ 41 | #define MODE1_RESTART 0x80 /**< Restart enabled */ 42 | // MODE2 bits 43 | #define MODE2_OUTNE_0 0x01 /**< Active LOW output enable input */ 44 | #define MODE2_OUTNE_1 0x02 /**< Active LOW output enable input - high impedience */ 45 | #define MODE2_OUTDRV 0x04 /**< totem pole structure vs open-drain */ 46 | #define MODE2_OCH 0x08 /**< Outputs change on ACK vs STOP */ 47 | #define MODE2_INVRT 0x10 /**< Output logic state inverted */ 48 | #define FREQUENCY_OSCILLATOR 25000000 /**< Int. osc. frequency in datasheet */ 49 | 50 | #define PCA9685_PRESCALE_MIN 3 /**< minimum prescale value */ 51 | #define PCA9685_PRESCALE_MAX 255 /**< maximum prescale value */ 52 | 53 | typedef struct{ 54 | I2C_HandleTypeDef *hi2c; 55 | uint8_t address; 56 | uint32_t oscillator_freq; 57 | }PCA9685_I2C; 58 | 59 | void PCA9685_begin(PCA9685_I2C* i2c, I2C_HandleTypeDef *hi2c, uint8_t address, uint8_t prescale); 60 | void PCA9685_reset(PCA9685_I2C* i2c); 61 | void PCA9685_sleep(PCA9685_I2C* i2c); 62 | void PCA9685_wakeup(PCA9685_I2C* i2c); 63 | void PCA9685_setExtClk(PCA9685_I2C* i2c, uint8_t prescale); 64 | void PCA9685_setPWMFreq(PCA9685_I2C* i2c, float freq); 65 | void PCA9685_setOutputMode(PCA9685_I2C* i2c, bool totempole); 66 | uint8_t PCA9685_readPrescale(PCA9685_I2C* i2c); 67 | uint8_t PCA9685_getPWM(PCA9685_I2C* i2c, uint8_t num); 68 | void PCA9685_setPWM(PCA9685_I2C* i2c, uint8_t num, uint16_t on, uint16_t off); 69 | void PCA9685_setPin(PCA9685_I2C* i2c, uint8_t num, uint16_t val, bool invert); 70 | void PCA9685_writeMicroseconds(PCA9685_I2C* i2c, uint8_t num, uint16_t Microseconds); 71 | uint32_t PCA9685_getOscillatorFrequency(PCA9685_I2C* i2c); 72 | void PCA9685_setOscillatorFrequency(PCA9685_I2C* i2c, uint32_t freq); 73 | 74 | 75 | #endif /* SRC_PCA9685_PWM_SERVO_PCA9685_H_ */ 76 | -------------------------------------------------------------------------------- /Optimized ILI9341 Touch LCD/Touch Screen/Touch_screen.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Touch_screen.h 3 | * 4 | * Created on: Jul 23, 2021 5 | * Author: Daniel Mårtensson 6 | */ 7 | 8 | #ifndef SRC_STM32_PLC_TOUCH_SCREEN_TOUCH_SCREEN_H_ 9 | #define SRC_STM32_PLC_TOUCH_SCREEN_TOUCH_SCREEN_H_ 10 | 11 | /* Necessary */ 12 | #include "../Open SAE J1939/Open SAE J1939/Structs.h" 13 | #include "../Open SAE J1939/SAE J1939/SAE J1939 Enums/Enum_NAME.h" 14 | #include 15 | #include 16 | #include 17 | #define DELIMITER "Å" /* This a separator for the text files - ASCII 143 - Å has the origins from 14th in Sweden */ 18 | 19 | /* Frames with no frame id */ 20 | void STM32_PLC_LCD_Show_Intro_Frame(); 21 | void STM32_PLC_LCD_Show_Main_Frame(uint8_t *frame_id, bool change_only_ABC_buttons); 22 | uint8_t STM32_PLC_LCD_Show_Numpad_Frame(bool decimalbutton_show, bool minusbutton_show, float *number_value, char title[]); 23 | uint8_t STM32_PLC_LCD_Show_Keyboard_Frame(char word[], char title[]); 24 | void STM32_PLC_LCD_Show_Plot_Frame(); 25 | 26 | /* Frame id 0 */ 27 | void STM32_PLC_LCD_Show_Measurement_And_Time_Frame(uint8_t *frame_id); 28 | void STM32_PLC_LCD_Show_Analog_Calibration_Frame(uint8_t *frame_id); 29 | void STM32_PLC_LCD_Show_PWM_Frequency_Settings_Frame(uint8_t *frame_id); 30 | 31 | /* Frame id 1 */ 32 | void STM32_PLC_LCD_Show_Logging_Frame(J1939 *j1939, uint8_t *frame_id); 33 | void STM32_PLC_LCD_Show_Control_Program_Settings_Frame(uint8_t *frame_id); 34 | void STM32_PLC_LCD_Show_Date_Time_Alarm_Settings_Frame(uint8_t *frame_id); 35 | 36 | /* Frame id 2 */ 37 | void STM32_PLC_LCD_Show_SAE_J1939_Request_Frame(J1939 *j1939, uint8_t *frame_id); 38 | void STM32_PLC_LCD_Show_SAE_J1939_Address_Frame(J1939 *j1939, uint8_t *frame_id); 39 | void STM32_PLC_LCD_Show_SAE_J1939_Commanded_Address_Frame(J1939 *j1939, uint8_t *frame_id); 40 | 41 | /* Frame id 3 */ 42 | void STM32_PLC_LCD_Show_SAE_J1939_This_ECU_DM1_Frame(J1939 *j1939, uint8_t *frame_id); 43 | void STM32_PLC_LCD_Show_SAE_J1939_Other_ECU_DM1_Frame(J1939 *j1939, uint8_t *frame_id); 44 | void STM32_PLC_LCD_Show_SAE_J1939_This_ECU_DM2_Frame(J1939 *j1939, uint8_t *frame_id); 45 | 46 | /* Frame id 4 */ 47 | void STM32_PLC_LCD_Show_SAE_J1939_Other_ECU_DM2_Frame(J1939 *j1939, uint8_t *frame_id); 48 | void STM32_PLC_LCD_Show_SAE_J1939_This_ECU_Name_Frame(J1939 *j1939, uint8_t *frame_id); 49 | void STM32_PLC_LCD_Show_SAE_J1939_Other_ECU_Name_Frame(J1939 *j1939, uint8_t *frame_id); 50 | 51 | /* Frame id 5 */ 52 | void STM32_PLC_LCD_Show_SAE_J1939_This_ECU_Identifications_Frame(J1939 *j1939, uint8_t *frame_id); 53 | void STM32_PLC_LCD_Show_SAE_J1939_Other_ECU_Identifications_Frame(J1939 *j1939, uint8_t *frame_id); 54 | void STM32_PLC_LCD_Show_Encoder_Revolutions_Settings_Frame(uint8_t *frame_id); 55 | 56 | /* Frame id 6 */ 57 | void STM32_PLC_LCD_Show_SDADC_Settings_Frame(uint8_t *frame_id); 58 | 59 | /* Dialogs */ 60 | uint8_t STM32_PLC_LCD_Show_Question_Yes_No_Dialog(char question[]); 61 | uint8_t STM32_PLC_LCD_Show_Information_OK_Dialog(char information[]); 62 | 63 | /* Logics */ 64 | void STM32_PLC_LCD_Call_Main_Logic(uint8_t *frame_id, J1939 *j1939); 65 | uint8_t STM32_PLC_LCD_Call_Numpad_Logic(bool decimalbutton_show, bool minusbutton_show, float *number_value); 66 | uint8_t STM32_PLC_LCD_Call_Keyboard_Logic(char word[]); 67 | uint8_t STM32_PLC_LCD_Call_Two_Button_Logic(uint16_t b1_x1, uint16_t b1_y1, uint16_t b1_x2, uint16_t b1_y2, uint16_t b2_x1, uint16_t b2_y1, uint16_t b2_x2, uint16_t b2_y2); 68 | uint8_t STM32_PLC_LCD_Call_One_Button_Logic(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2); 69 | 70 | /* Automatic Control Program */ 71 | void STM32_PLC_LCD_Set_Control_Program(uint8_t program_number); 72 | void STM32_PLC_LCD_Set_Program_Parameters(float parameters[]); 73 | uint8_t STM32_PLC_LCD_Get_Control_Program(); 74 | void STM32_PLC_LCD_Execute_Control_Program(J1939 *j1939); 75 | 76 | #endif /* SRC_STM32_PLC_TOUCH_SCREEN_TOUCH_SCREEN_H_ */ 77 | -------------------------------------------------------------------------------- /Optimized ILI9341 Touch LCD/Touch Screen/Logics/Keyboard_logic.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Numpad_frame.c 3 | * 4 | * Created on: Jul 29, 2021 5 | * Author: Daniel Mårtensson 6 | */ 7 | 8 | #include "../Touch_screen.h" 9 | #include "../Hardware/ILI9341.h" 10 | 11 | static void shift_keyboard(uint8_t keyboard_page); 12 | 13 | uint8_t STM32_PLC_LCD_Call_Keyboard_Logic(char word[]) { 14 | char text[17] = ""; 15 | uint8_t k = 0; 16 | uint8_t keyboard_page = 6; /* We start at this */ 17 | while (1) { 18 | if (TSC2046_isPressed()) { 19 | TSC2046_GetTouchData(); 20 | uint16_t X = lcd.myTsData.X; 21 | uint16_t Y = lcd.myTsData.Y; 22 | if (X >= 23 && X <= 63 && Y >= 70 && Y <= 110) { 23 | /* 0 */ 24 | if (k >= 0 && k < 16) { 25 | text[k] = 0 + 32 + 5*keyboard_page; 26 | k++; 27 | } 28 | } else if (X >= 81 && X <= 121 && Y >= 70 && Y <= 110) { 29 | /* 1 */ 30 | if (k < 16) { 31 | text[k] = 1 + 32 + 5*keyboard_page; 32 | k++; 33 | } 34 | } else if (X >= 139 && X <= 179 && Y >= 70 && Y <= 110) { 35 | /* 2 */ 36 | if (k < 16) { 37 | text[k] = 2 + 32 + 5*keyboard_page; 38 | k++; 39 | } 40 | } else if (X >= 197 && X <= 237 && Y >= 70 && Y <= 110) { 41 | /* 3 */ 42 | if (k < 16) { 43 | text[k] = 3 + 32 + 5*keyboard_page; 44 | k++; 45 | } 46 | } else if (X >= 255 && X <= 295 && Y >= 70 && Y <= 110) { 47 | /* 4 */ 48 | if (k < 16) { 49 | text[k] = 4 + 32 + 5*keyboard_page; 50 | k++; 51 | } 52 | } else if (X >= 23 && X <= 63 && Y >= 125 && Y <= 165) { 53 | /* 5 */ 54 | if (k < 16) { 55 | text[k] = 0 + 5 + 32 + 5*keyboard_page; 56 | k++; 57 | } 58 | } else if (X >= 81 && X <= 121 && Y >= 125 && Y <= 165) { 59 | /* 6 */ 60 | if (k < 16) { 61 | text[k] = 1 + 5 + 32 + 5*keyboard_page; 62 | k++; 63 | } 64 | } else if (X >= 139 && X <= 179 && Y >= 125 && Y <= 165) { 65 | /* 7 */ 66 | if (k < 16) { 67 | text[k] = 2 + 5 + 32 + 5*keyboard_page; 68 | k++; 69 | } 70 | } else if (X >= 197 && X <= 237 && Y >= 125 && Y <= 165) { 71 | /* 8 */ 72 | if (k < 16) { 73 | text[k] = 3 + 5 + 32 + 5*keyboard_page; 74 | k++; 75 | } 76 | } else if (X >= 255 && X <= 295 && Y >= 125 && Y <= 165) { 77 | /* 9 */ 78 | if (k < 16) { 79 | text[k] = 4 + 5 + 32 + 5*keyboard_page; 80 | k++; 81 | } 82 | } else if (X >= 23 && X <= 63 && Y >= 180 && Y <= 220) { 83 | /* < */ 84 | if(keyboard_page > 0){ 85 | keyboard_page--; 86 | shift_keyboard(keyboard_page); 87 | } 88 | } else if (X >= 81 && X <= 121 && Y >= 180 && Y <= 220) { 89 | /* > */ 90 | if(keyboard_page < 17){ 91 | keyboard_page++; 92 | shift_keyboard(keyboard_page); 93 | } 94 | } else if (X >= 139 && X <= 179 && Y >= 180 && Y <= 220) { 95 | /* C */ 96 | memset(text, 0, sizeof(text)); 97 | k = 0; 98 | ILI9341_fill_rect(12, 24, 308, 50, COLOR_WHITE); /* Clear white space above */ 99 | } else if (X >= 197 && X <= 237 && Y >= 180 && Y <= 220) { 100 | /* <- */ 101 | return 0; 102 | } else if (X >= 255 && X <= 295 && Y >= 180 && Y <= 220) { 103 | /* OK */ 104 | memcpy(word, text, 17); 105 | return 1; 106 | } 107 | /* Display the selected number text */ 108 | ILI9341_print_text(text, 15, 25, COLOR_BLACK, COLOR_WHITE, 3); 109 | } 110 | } 111 | } 112 | 113 | static void shift_keyboard(uint8_t keyboard_page) { 114 | char letter[2]; 115 | uint16_t x = 0; 116 | for(uint8_t i = 0; i < 5; i++) { 117 | /* Jump one step to the left */ 118 | x += 23; 119 | 120 | /* Upper letters */ 121 | sprintf(letter, "%c", i + 32 + 5*keyboard_page); 122 | ILI9341_print_text(letter, x + 16, 83, COLOR_BLACK, COLOR_WHITE, 2); 123 | 124 | /* Down letter */ 125 | sprintf(letter, "%c", i + 5 + 32 + 5*keyboard_page); 126 | ILI9341_print_text(letter, x + 16, 138, COLOR_BLACK, COLOR_WHITE, 2); 127 | 128 | /* Jump one step to the left */ 129 | x += 35; 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /LiquidCrystal I2C/LiquidCrystal_I2C.h: -------------------------------------------------------------------------------- 1 | //Daniel Mårtensson 2 | #ifndef LiquidCrystal_I2C_h 3 | #define LiquidCrystal_I2C_h 4 | 5 | #include "main.h" 6 | 7 | // commands 8 | #define LCD_CLEARDISPLAY 0x01 9 | #define LCD_RETURNHOME 0x02 10 | #define LCD_ENTRYMODESET 0x04 11 | #define LCD_DISPLAYCONTROL 0x08 12 | #define LCD_CURSORSHIFT 0x10 13 | #define LCD_FUNCTIONSET 0x20 14 | #define LCD_SETCGRAMADDR 0x40 15 | #define LCD_SETDDRAMADDR 0x80 16 | 17 | // flags for display entry mode 18 | #define LCD_ENTRYRIGHT 0x00 19 | #define LCD_ENTRYLEFT 0x02 20 | #define LCD_ENTRYSHIFTINCREMENT 0x01 21 | #define LCD_ENTRYSHIFTDECREMENT 0x00 22 | 23 | // flags for display on/off control 24 | #define LCD_DISPLAYON 0x04 25 | #define LCD_DISPLAYOFF 0x00 26 | #define LCD_CURSORON 0x02 27 | #define LCD_CURSOROFF 0x00 28 | #define LCD_BLINKON 0x01 29 | #define LCD_BLINKOFF 0x00 30 | 31 | // flags for display/cursor shift 32 | #define LCD_DISPLAYMOVE 0x08 33 | #define LCD_CURSORMOVE 0x00 34 | #define LCD_MOVERIGHT 0x04 35 | #define LCD_MOVELEFT 0x00 36 | 37 | // flags for function set 38 | #define LCD_8BITMODE 0x10 39 | #define LCD_4BITMODE 0x00 40 | #define LCD_2LINE 0x08 41 | #define LCD_1LINE 0x00 42 | #define LCD_5x10DOTS 0x04 43 | #define LCD_5x8DOTS 0x00 44 | 45 | // flags for backlight control 46 | #define LCD_BACKLIGHT 0x08 47 | #define LCD_NOBACKLIGHT 0x00 48 | 49 | #define En 0b00000100 // Enable bit 50 | #define Rw 0b00000010 // Read/Write bit 51 | #define Rs 0b00000001 // Register select bit 52 | 53 | // Booleans 54 | #define TRUE 1 55 | #define FALSE 0 56 | 57 | typedef struct { 58 | uint8_t _Addr; 59 | uint8_t _displayfunction; 60 | uint8_t _displaycontrol; 61 | uint8_t _displaymode; 62 | uint8_t _numlines; 63 | uint8_t _oled; // Initial false 64 | uint8_t _cols; 65 | uint8_t _rows; 66 | uint8_t _backlightval; 67 | uint8_t _charsize; // E.g charsize = LCD_5x8DOTS 68 | I2C_HandleTypeDef* hi2c; 69 | } LiquidCrystal_LCD; 70 | 71 | void LiquidCrystal_I2C(LiquidCrystal_LCD* lcd, I2C_HandleTypeDef* hi2c, uint8_t lcd_Addr, uint8_t lcd_cols, uint8_t lcd_rows); 72 | void clear(LiquidCrystal_LCD* lcd); 73 | void home(LiquidCrystal_LCD* lcd); 74 | void noDisplay(LiquidCrystal_LCD* lcd); 75 | void display(LiquidCrystal_LCD* lcd); 76 | void noBlink(LiquidCrystal_LCD* lcd); 77 | void blink(LiquidCrystal_LCD* lcd); 78 | void noCursor(LiquidCrystal_LCD* lcd); 79 | void cursor(LiquidCrystal_LCD* lcd); 80 | void scrollDisplayLeft(LiquidCrystal_LCD* lcd); 81 | void scrollDisplayRight(LiquidCrystal_LCD* lcd); 82 | void printLeft(LiquidCrystal_LCD* lcd); 83 | void printRight(LiquidCrystal_LCD* lcd); 84 | void leftToRight(LiquidCrystal_LCD* lcd); 85 | void rightToLeft(LiquidCrystal_LCD* lcd); 86 | void shiftIncrement(LiquidCrystal_LCD* lcd); 87 | void shiftDecrement(LiquidCrystal_LCD* lcd); 88 | void noBacklight(LiquidCrystal_LCD* lcd); 89 | void backlight(LiquidCrystal_LCD* lcd); 90 | void autoscroll(LiquidCrystal_LCD* lcd); 91 | void noAutoscroll(LiquidCrystal_LCD* lcd); 92 | void createChar(LiquidCrystal_LCD* lcd, uint8_t location, uint8_t charmap[]); // Example: uint8_t charmap[8] = {0b00100,0b01110,0b01110,0b01110,0b11111,0b00000,0b00100,0b00000}; 93 | void setCursor(LiquidCrystal_LCD* lcd, uint8_t, uint8_t); 94 | void write(LiquidCrystal_LCD* lcd, uint8_t); 95 | void command(LiquidCrystal_LCD* lcd, uint8_t); 96 | void init(LiquidCrystal_LCD* lcd); 97 | void oled_init(LiquidCrystal_LCD* lcd); 98 | void printToLCD(LiquidCrystal_LCD* lcd, char* string, uint8_t length); 99 | 100 | /* 101 | * compatibility API function aliases 102 | */ 103 | void blink_on(LiquidCrystal_LCD* lcd); // alias for blink() 104 | void blink_off(LiquidCrystal_LCD* lcd); // alias for noBlink() 105 | void cursor_on(LiquidCrystal_LCD* lcd); // alias for cursor() 106 | void cursor_off(LiquidCrystal_LCD* lcd); // alias for noCursor() 107 | void setBacklight(LiquidCrystal_LCD* lcd, uint8_t ON); // alias for backlight() and nobacklight() 108 | void load_custom_character(LiquidCrystal_LCD* lcd, uint8_t char_num, uint8_t *rows); // alias for createChar() 109 | 110 | #endif 111 | -------------------------------------------------------------------------------- /Optimized ILI9341 Touch LCD/Touch Screen/Frames/Main_frame.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Main_frame.c 3 | * 4 | * Created on: Jul 23, 2021 5 | * Author: Daniel Mårtensson 6 | */ 7 | 8 | #include "../Touch_screen.h" 9 | #include "../Hardware/ILI9341.h" 10 | 11 | /* Create the main frame */ 12 | void STM32_PLC_LCD_Show_Main_Frame(uint8_t *frame_id, bool change_only_ABC_buttons) { 13 | /* Set rotation */ 14 | ILI9341_set_rotation(2); 15 | 16 | if(!change_only_ABC_buttons) { 17 | /* Set background */ 18 | ILI9341_fill_screen(COLOR_NAVY); 19 | 20 | /* Print frame - large square */ 21 | ILI9341_draw_horizontal_line(5, 235, 310, COLOR_GREEN); 22 | ILI9341_draw_horizontal_line(5, 5, 310, COLOR_GREEN); 23 | ILI9341_draw_vertical_line(5, 5, 230, COLOR_GREEN); 24 | ILI9341_draw_vertical_line(315, 5, 230, COLOR_GREEN); 25 | 26 | /* Print buttons - Small squares */ 27 | ILI9341_draw_vertical_line(50, 5, 230, COLOR_GREEN); 28 | ILI9341_draw_horizontal_line(5, 49, 45, COLOR_GREEN); 29 | ILI9341_draw_horizontal_line(5, 96, 45, COLOR_GREEN); 30 | ILI9341_draw_horizontal_line(5, 143, 45, COLOR_GREEN); 31 | ILI9341_draw_horizontal_line(5, 190, 45, COLOR_GREEN); 32 | ILI9341_draw_horizontal_line(5, 235, 45, COLOR_GREEN); 33 | 34 | /* This line is for the input and output text */ 35 | ILI9341_draw_horizontal_line(50, 30, 265, COLOR_GREEN); 36 | } 37 | /* Apply them */ 38 | char text[40]; 39 | sprintf(text, "%c", 65 + 3 * *frame_id); /* A */ 40 | ILI9341_print_text(text, 18, 13, COLOR_YELLOW, COLOR_NAVY, 4); 41 | sprintf(text, "%c", 66 + 3 * *frame_id); /* B */ 42 | ILI9341_print_text(text, 18, 59, COLOR_CYAN, COLOR_NAVY, 4); 43 | sprintf(text, "%c", 67 + 3 * *frame_id); /* C */ 44 | ILI9341_print_text(text, 18, 106, COLOR_MAGENTA, COLOR_NAVY, 4); 45 | if(!change_only_ABC_buttons) { 46 | ILI9341_print_text("<-", 10, 156, COLOR_ORANGE, COLOR_NAVY, 3); 47 | ILI9341_print_text("->", 14, 202, COLOR_GREEN, COLOR_NAVY, 3); 48 | 49 | /* Print title */ 50 | ILI9341_print_text("Main frame", 55, 10, COLOR_YELLOW, COLOR_NAVY, 2); 51 | 52 | /* Write out letters */ 53 | sprintf(text, "A:Show measurement and time"); 54 | ILI9341_print_text(text, 55, 35, COLOR_YELLOW, COLOR_NAVY, 1); 55 | sprintf(text, "B:Set analog calibration"); 56 | ILI9341_print_text(text, 55, 45, COLOR_YELLOW, COLOR_NAVY, 1); 57 | sprintf(text, "C:Set PWM frequencies"); 58 | ILI9341_print_text(text, 55, 55, COLOR_YELLOW, COLOR_NAVY, 1); 59 | sprintf(text, "D:Store measurements to SD card"); 60 | ILI9341_print_text(text, 55, 65, COLOR_YELLOW, COLOR_NAVY, 1); 61 | sprintf(text, "E:Set control program"); 62 | ILI9341_print_text(text, 55, 75, COLOR_YELLOW, COLOR_NAVY, 1); 63 | sprintf(text, "F:Set date and time and alarm"); 64 | ILI9341_print_text(text, 55, 85, COLOR_YELLOW, COLOR_NAVY, 1); 65 | sprintf(text, "G:Do a PGN request"); 66 | ILI9341_print_text(text, 55, 95, COLOR_YELLOW, COLOR_NAVY, 1); 67 | sprintf(text, "H:Show ECU addresses"); 68 | ILI9341_print_text(text, 55, 105, COLOR_YELLOW, COLOR_NAVY, 1); 69 | sprintf(text, "I:Commanded address"); 70 | ILI9341_print_text(text, 55, 115, COLOR_YELLOW, COLOR_NAVY, 1); 71 | sprintf(text, "J:Show this ECU DM1 codes"); 72 | ILI9341_print_text(text, 55, 125, COLOR_YELLOW, COLOR_NAVY, 1); 73 | sprintf(text, "K:Show other ECU DM1 codes"); 74 | ILI9341_print_text(text, 55, 135, COLOR_YELLOW, COLOR_NAVY, 1); 75 | sprintf(text, "L:Show this ECU DM2 codes"); 76 | ILI9341_print_text(text, 55, 145, COLOR_YELLOW, COLOR_NAVY, 1); 77 | sprintf(text, "M:Show other ECU DM2 codes"); 78 | ILI9341_print_text(text, 55, 155, COLOR_YELLOW, COLOR_NAVY, 1); 79 | sprintf(text, "N:Show this ECU name"); 80 | ILI9341_print_text(text, 55, 165, COLOR_YELLOW, COLOR_NAVY, 1); 81 | sprintf(text, "O:Show other ECU name"); 82 | ILI9341_print_text(text, 55, 175, COLOR_YELLOW, COLOR_NAVY, 1); 83 | sprintf(text, "P:Show this ECU identifications"); 84 | ILI9341_print_text(text, 55, 185, COLOR_YELLOW, COLOR_NAVY, 1); 85 | sprintf(text, "Q:Show other ECU identifications"); 86 | ILI9341_print_text(text, 55, 195, COLOR_YELLOW, COLOR_NAVY, 1); 87 | sprintf(text, "R:Set pulses per encoder revolution"); 88 | ILI9341_print_text(text, 55, 195, COLOR_YELLOW, COLOR_NAVY, 1); 89 | sprintf(text, "S:Set gain and offset for ADC/DADC"); 90 | ILI9341_print_text(text, 55, 205, COLOR_YELLOW, COLOR_NAVY, 1); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /Optimized ILI9341 Touch LCD/Touch Screen/Frames/Encoder_revolutions_settings_frame.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Encoder_revolutions_settings_frame.c 3 | * 4 | * Created on: 25 juli 2021 5 | * Author: Daniel Mårtensson 6 | */ 7 | 8 | #include "../Touch_screen.h" 9 | #include "../Hardware/ILI9341.h" 10 | #include "../../Functions.h" 11 | 12 | void STM32_PLC_LCD_Show_Encoder_Revolutions_Settings_Frame(uint8_t *frame_id) { 13 | /* Clear the screen , but not the icons */ 14 | ILI9341_fill_rect(51, 6, 314, 234, COLOR_NAVY); 15 | 16 | /* Write the title */ 17 | ILI9341_draw_horizontal_line(50, 30, 265, COLOR_GREEN); 18 | ILI9341_print_text("Set encoder revolution", 55, 10, COLOR_YELLOW, COLOR_NAVY, 1); 19 | 20 | /* Show all calibration inputs */ 21 | ILI9341_print_text("Encoder counts between:", 55, 35, COLOR_YELLOW, COLOR_NAVY, 1); 22 | ILI9341_print_text("-32767 to 32767", 55, 45, COLOR_YELLOW, COLOR_NAVY, 1); 23 | ILI9341_print_text("Set how many pulses one", 55, 55, COLOR_YELLOW, COLOR_NAVY, 1); 24 | ILI9341_print_text("revolution is for encoder:", 55, 65, COLOR_YELLOW, COLOR_NAVY, 1); 25 | 26 | /* Show selected frequency */ 27 | if(STM32_PLC_SD_Mont_Card() != FR_OK){ 28 | STM32_PLC_LCD_Show_Information_OK_Dialog("Could not mount SD card"); 29 | STM32_PLC_LCD_Show_Main_Frame(frame_id, false); 30 | return; 31 | } 32 | STM32_PLC_SD_Open_Existing_File_With_Read("ENCODER.TXT"); 33 | char text[50]; 34 | STM32_PLC_SD_Read_File(text, sizeof(text)); 35 | STM32_PLC_SD_Close_File(); 36 | STM32_PLC_SD_Unmount_Card(); 37 | uint16_t pulses_per_revolution_0 = atoi(strtok(text, DELIMITER)); 38 | uint16_t pulses_per_revolution_1 = atoi(strtok(NULL, DELIMITER)); 39 | ILI9341_print_text("Current settings:", 55, 75, COLOR_YELLOW, COLOR_NAVY, 1); 40 | sprintf(text, "Encoder0:%i Encoder1:%i", pulses_per_revolution_0, pulses_per_revolution_1); 41 | ILI9341_print_text(text, 55, 85, COLOR_YELLOW, COLOR_NAVY, 1); 42 | 43 | /* Select settings button */ 44 | ILI9341_fill_rect(90, 195, 273, 220, COLOR_GREEN); 45 | ILI9341_hollow_rect(90, 195, 273, 220, COLOR_BLACK); 46 | ILI9341_print_text("Select encoder", 100, 200, COLOR_BLACK, COLOR_GREEN, 2); 47 | 48 | /* Logic for request button */ 49 | STM32_PLC_LCD_Call_One_Button_Logic(90, 195, 273, 220); 50 | 51 | /* Ask the user if */ 52 | if(STM32_PLC_LCD_Show_Question_Yes_No_Dialog("Do you want to set encoder revolution?") == 0) { 53 | STM32_PLC_LCD_Show_Main_Frame(frame_id, false); 54 | return; 55 | } 56 | 57 | /* You entered choice 1 - Show numpad */ 58 | bool minusbutton_show = false; 59 | bool decimalbutton_show = false; 60 | float number_value; 61 | if(STM32_PLC_LCD_Show_Numpad_Frame(decimalbutton_show, minusbutton_show, &number_value, "Enter input number between 1 and 32767") == 0) { 62 | STM32_PLC_LCD_Show_Main_Frame(frame_id, false); 63 | return; 64 | } 65 | 66 | /* Check */ 67 | uint16_t pulses_per_revolution; 68 | if(number_value < 1) 69 | pulses_per_revolution = 1; 70 | else if(number_value > 32767) 71 | pulses_per_revolution = 32767; 72 | else 73 | pulses_per_revolution = (uint16_t) number_value; 74 | 75 | /* Ask for which PWM */ 76 | if(STM32_PLC_LCD_Show_Numpad_Frame(decimalbutton_show, minusbutton_show, &number_value, "Set setting for Encoder0=0 or Encoder1=1") == 0) { 77 | STM32_PLC_LCD_Show_Main_Frame(frame_id, false); 78 | return; 79 | } 80 | 81 | /* Check */ 82 | uint8_t encoder_choice; 83 | if(number_value < 0) 84 | encoder_choice = 0; 85 | else if(number_value > 1) 86 | encoder_choice = 1; 87 | else 88 | encoder_choice = (uint8_t) number_value; 89 | 90 | /* Apply them */ 91 | STM32_PLC_Encoder_Set_Pulses_Per_Revolutions(encoder_choice, pulses_per_revolution); 92 | 93 | /* Mount */ 94 | if(STM32_PLC_SD_Mont_Card() != FR_OK){ 95 | STM32_PLC_LCD_Show_Information_OK_Dialog("Could not mount SD card"); 96 | STM32_PLC_LCD_Show_Main_Frame(frame_id, false); 97 | return; 98 | } 99 | 100 | /* Overwrite */ 101 | if(encoder_choice == 0) 102 | pulses_per_revolution_0 = pulses_per_revolution; 103 | else 104 | pulses_per_revolution_1 = pulses_per_revolution; 105 | 106 | /* Write */ 107 | STM32_PLC_SD_Open_Existing_File_With_Write("ENCODER.TXT"); 108 | sprintf(text, "%i%s%i", pulses_per_revolution_0, DELIMITER, pulses_per_revolution_1); 109 | STM32_PLC_SD_Write_File(text); 110 | STM32_PLC_SD_Close_File(); 111 | STM32_PLC_SD_Unmount_Card(); 112 | STM32_PLC_LCD_Show_Main_Frame(frame_id, false); 113 | } 114 | -------------------------------------------------------------------------------- /VL6180X/Distribution/Unscented_Kalman_Filter.m: -------------------------------------------------------------------------------- 1 | function Unscented_Kalman_Filter() 2 | 3 | % Initial parameters 4 | L = 1; 5 | a = 0.5; 6 | b = 2; 7 | k = 1; 8 | Q = 0.0001; 9 | R = 2; 10 | P = 1; 11 | xhat = 15; 12 | zk = 13; 13 | 14 | % Read the data 15 | fid = csvread('log.txt')'; 16 | l = 500; 17 | 18 | % Filtered data 19 | X = zeros(1, l); 20 | 21 | for i = 1:l 22 | 23 | % Get measurement 24 | zk = fid(i); 25 | 26 | % Save UKF value 27 | X(i) = xhat; 28 | 29 | % UKF filter 30 | [xhat, P] = ukf(xhat, zk, P, Q, R, a, k, b, L); 31 | end 32 | 33 | close all 34 | plot(1:l, X, 'r', 1:l, fid(1:l), 'b'); 35 | legend('UKF', 'Real') 36 | grid on 37 | end 38 | 39 | function [xhat, P] = ukf(xhat, zk, P, Q, R, a, k, b, L) 40 | % Init - Create the weights 41 | [Wa, Wc] = ukf_create_weights(a, b, k, L); 42 | 43 | % PREDICT: Step 0 - Predict the state and state estimation error covariance at the next time step 44 | s = ukf_compute_sigma_points(xhat, P, a, k, L); 45 | 46 | % PREDICT: Step 1 - Run our transition function 47 | x = ukf_transition(s, L); 48 | 49 | % PREDICT: Step 2 - Combine the predicted states to obtain the predicted states 50 | xhat = ukf_multiply_weights(x, Wa, L); 51 | 52 | % PREDICT: Step 3 - Compute the covariance of the predicted state 53 | P = ukf_estimate_covariance(x, xhat, Wc, Q, L); 54 | 55 | % UPDATE: Step 1 - Use the nonlinear measurement function to compute the predicted measurements for each of the sigma points. 56 | z = s; % Here we assume that the observation function z = h(s, u) = s 57 | 58 | % UPDATE: Step 2 - Combine the predicted measurements to obtain the predicted measurement 59 | zhat = ukf_multiply_weights(z, Wa, L); 60 | 61 | % UPDATE: Step 3 - Estimate the covariance of the predicted measurement 62 | Shat = ukf_estimate_covariance(z, zhat, Wc, R, L); 63 | 64 | % UPDATE: Step 4 - Estimate the cross-covariance between xhat and zhat. 65 | Csz = ukf_estimate_cross_covariance(s, xhat, z, zhat, Wc, L); 66 | 67 | % UPDATE: Step 5 - Find kalman K matrix 68 | K = ukf_create_kalman_K(Shat, Csz, L); 69 | 70 | % UPDATE: Step 6 - Obtain the estimated state and state estimation error covariance 71 | [xhat, P] = ukf_state_update(K, Shat, P, xhat, zk, zhat, L); 72 | 73 | end 74 | 75 | function [Wa, Wc] = ukf_create_weights(a, b, k, L) 76 | N = 2 * L + 1; 77 | Wa = zeros(1, N); 78 | Wc = zeros(1, N); 79 | for i = 1:N 80 | if(i == 1) 81 | Wa(i) = (a*a*k-L)/(a*a*k); 82 | Wc(i) = Wa(i) + 1 - a*a + b; 83 | else 84 | Wa(i) = 1/(2*a*a*k); 85 | Wc(i) = Wa(i); 86 | end 87 | end 88 | end 89 | 90 | function [s] = ukf_compute_sigma_points(x, P, a, k, L) 91 | N = 2 * L + 1; 92 | compensate = L + 1; 93 | s = zeros(L, N); 94 | A = a*sqrt(k)*chol(P); 95 | for j = 1:N 96 | if(j == 1) 97 | s(:, j) = x; 98 | elseif(and(j >= 2, j <= L + 1)) 99 | s(:, j) = x + A(:, j - 1); 100 | else 101 | s(:, j) = x - A(:, j - compensate); 102 | end 103 | end 104 | end 105 | 106 | function x = ukf_multiply_weights(xi, W, L) 107 | N = 2 * L + 1; 108 | x = zeros(L, 1); 109 | for i = 1:N 110 | x = x + W(i)*xi(:, i); 111 | end 112 | end 113 | 114 | function P = ukf_estimate_covariance(xi, x, W, O, L) 115 | N = 2 * L + 1; 116 | P = zeros(L, L); 117 | for i = 1:N 118 | P = P + W(i)*(xi(:, i) - x)*(xi(:, i) - x)'; 119 | end 120 | P = P + O; 121 | end 122 | 123 | function Csz = ukf_estimate_cross_covariance(s, xhat, z, zhat, Wc, L) 124 | N = 2 * L + 1; 125 | Csz = zeros(L, L); 126 | for i = 1:N 127 | Csz = Csz + Wc(i)*(s(:, i) - xhat)*(z(:, i) - zhat)'; 128 | end 129 | end 130 | 131 | function K = ukf_create_kalman_K(Shat, Csz, L) 132 | K = zeros(L, L); 133 | for i = 1:L 134 | % Solve Ax = b with Cholesky 135 | A = chol(Shat, 'lower'); 136 | y = linsolve(A, Csz(:, i)); 137 | K(:, i) = linsolve(A', y); 138 | end 139 | end 140 | 141 | function [xhat, P] = ukf_state_update(K, Shat, P, xhat, zk, zhat, L) 142 | xhat = xhat + K*(zk - zhat); 143 | P = P - K*Shat*K'; 144 | end 145 | 146 | function x = ukf_transition(s, L) 147 | N = 2 * L + 1; 148 | x = zeros(L, 1); 149 | for i = 1:N 150 | x(i) = std(s(:, i))*randn + mean(s(:, i)); % std*random_variable + average = Gaussian distribution 151 | end 152 | end 153 | -------------------------------------------------------------------------------- /Optimized ILI9341 Touch LCD/Touch Screen/Frames/Tools/Plot_frame.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Plot_frame.c 3 | * 4 | * Created on: 1 aug. 2021 5 | * Author: Daniel Mårtensson 6 | */ 7 | 8 | #include "../../Touch_screen.h" 9 | #include "../../Hardware/ILI9341.h" 10 | #include "../../../Functions.h" 11 | 12 | static void add_spaces(uint8_t length, char text[]); 13 | 14 | void STM32_PLC_LCD_Show_Plot_Frame() { 15 | /* ADC 0 to ADC 2 */ 16 | char text[60]; 17 | sprintf(text, "ADC0:%0.2f ADC1:%0.2f ADC2:%0.2f", STM32_PLC_Analog_Input_ADC_Get(0), STM32_PLC_Analog_Input_ADC_Get(1), STM32_PLC_Analog_Input_ADC_Get(2)); 18 | add_spaces(43, text); 19 | ILI9341_print_text(text, 55, 35, COLOR_YELLOW, COLOR_NAVY, 1); 20 | 21 | /* ADC3 to ADC5 */ 22 | sprintf(text, "ADC3:%0.2f ADC4:%0.2f ADC5:%0.2f", STM32_PLC_Analog_Input_ADC_Get(3), STM32_PLC_Analog_Input_ADC_Get(4), STM32_PLC_Analog_Input_ADC_Get(5)); 23 | add_spaces(43, text); 24 | ILI9341_print_text(text, 55, 45, COLOR_YELLOW, COLOR_NAVY, 1); 25 | 26 | /* ADC6 to ADC8 */ 27 | sprintf(text, "ADC6:%0.2f ADC5:%0.2f ADC8:%0.2f", STM32_PLC_Analog_Input_ADC_Get(6), STM32_PLC_Analog_Input_ADC_Get(5), STM32_PLC_Analog_Input_ADC_Get(8)); 28 | add_spaces(43, text); 29 | ILI9341_print_text(text, 55, 55, COLOR_YELLOW, COLOR_NAVY, 1); 30 | 31 | /* ADC9 to ADC11 */ 32 | sprintf(text, "ADC9:%0.2f ADC10:%0.2f ADC11:%0.2f", STM32_PLC_Analog_Input_ADC_Get(9), STM32_PLC_Analog_Input_ADC_Get(10), STM32_PLC_Analog_Input_ADC_Get(11)); 33 | add_spaces(43, text); 34 | ILI9341_print_text(text, 55, 65, COLOR_YELLOW, COLOR_NAVY, 1); 35 | 36 | /* DADC0 to DADC2 */ 37 | sprintf(text, "DADC0:%0.2f DADC1:%0.2f DADC2:%0.2f", STM32_PLC_Analog_Input_DADC_Get(0), STM32_PLC_Analog_Input_DADC_Get(1), STM32_PLC_Analog_Input_DADC_Get(2)); 38 | add_spaces(43, text); 39 | ILI9341_print_text(text, 55, 75, COLOR_YELLOW, COLOR_NAVY, 1); 40 | 41 | /* DADC3 to DADC4 */ 42 | sprintf(text, "DADC3:%0.2f DADC4:%0.2f", STM32_PLC_Analog_Input_DADC_Get(3), STM32_PLC_Analog_Input_DADC_Get(4)); 43 | add_spaces(43, text); 44 | ILI9341_print_text(text, 55, 85, COLOR_YELLOW, COLOR_NAVY, 1); 45 | 46 | /* DI0 to DI3 */ 47 | sprintf(text, "DI0:%i DI1:%i DI2:%i DI3:%i", STM32_PLC_Digital_Input_Get(0), STM32_PLC_Digital_Input_Get(1), STM32_PLC_Digital_Input_Get(2), STM32_PLC_Digital_Input_Get(3)); 48 | add_spaces(43, text); 49 | ILI9341_print_text(text, 55, 95, COLOR_YELLOW, COLOR_NAVY, 1); 50 | 51 | /* DI4 to DI7 */ 52 | sprintf(text, "DI4:%i DI5:%i DI6:%i DI7:%i", STM32_PLC_Digital_Input_Get(4), STM32_PLC_Digital_Input_Get(5), STM32_PLC_Digital_Input_Get(6), STM32_PLC_Digital_Input_Get(7)); 53 | add_spaces(43, text); 54 | ILI9341_print_text(text, 55, 105, COLOR_YELLOW, COLOR_NAVY, 1); 55 | 56 | /* E0 to E1 */ 57 | sprintf(text, "E0:%f E1:%f", STM32_PLC_Encoder_Get(0), STM32_PLC_Encoder_Get(1)); 58 | add_spaces(43, text); 59 | ILI9341_print_text(text, 55, 115, COLOR_YELLOW, COLOR_NAVY, 1); 60 | 61 | /* IC0 to IC2 */ 62 | sprintf(text, "IC0:%f IC1:%f", STM32_PLC_Input_Capture_Get(0), STM32_PLC_Input_Capture_Get(1)); 63 | add_spaces(43, text); 64 | ILI9341_print_text(text, 55, 125, COLOR_YELLOW, COLOR_NAVY, 1); 65 | 66 | /* DAC0 to DAC2 */ 67 | sprintf(text, "DAC0:%i DAC1:%i DAC2:%i", STM32_PLC_Analog_Output_Get(0), STM32_PLC_Analog_Output_Get(1), STM32_PLC_Analog_Output_Get(2)); 68 | add_spaces(43, text); 69 | ILI9341_print_text(text, 55, 135, COLOR_YELLOW, COLOR_NAVY, 1); 70 | 71 | /* PWM0 to PWM3 */ 72 | sprintf(text, "PWM0:%i PWM1:%i PWM2:%i PWM3:%i", STM32_PLC_PWM_Get(0), STM32_PLC_PWM_Get(1), STM32_PLC_PWM_Get(2), STM32_PLC_PWM_Get(3)); 73 | add_spaces(43, text); 74 | ILI9341_print_text(text, 55, 145, COLOR_YELLOW, COLOR_NAVY, 1); 75 | 76 | /* PWM4 to PWM7 */ 77 | sprintf(text, "PWM4:%i PWM5:%i PWM6:%i PWM7:%i", STM32_PLC_PWM_Get(4), STM32_PLC_PWM_Get(5), STM32_PLC_PWM_Get(6), STM32_PLC_PWM_Get(7)); 78 | add_spaces(43, text); 79 | ILI9341_print_text(text, 55, 155, COLOR_YELLOW, COLOR_NAVY, 1); 80 | 81 | /* Display date & time */ 82 | uint8_t date; 83 | uint8_t month; 84 | uint8_t year; 85 | uint8_t seconds; 86 | uint8_t minutes; 87 | uint8_t hours; 88 | STM32_PLC_RTC_Get_Time(&seconds, &minutes, &hours); 89 | STM32_PLC_RTC_Get_Date(&date, &month, &year); 90 | sprintf(text, "Date:%i-%i-%i Time:%i:%i:%i", 2000 + year, month, date, hours, minutes, seconds); 91 | add_spaces(43, text); 92 | ILI9341_print_text(text, 55, 165, COLOR_YELLOW, COLOR_NAVY, 1); 93 | } 94 | 95 | static void add_spaces(uint8_t length, char text[]){ 96 | /* This is for removing old values from LCD */ 97 | for(uint8_t i = strlen(text); i < length; i++) 98 | text[i] = ' '; 99 | text[length] = '\0'; 100 | } 101 | -------------------------------------------------------------------------------- /Optimized ILI9341 Touch LCD/Touch Screen/Frames/Date_time_alarm_settings_frame.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Date_time_alarm_settings_frame.c 3 | * 4 | * Created on: Jul 26, 2021 5 | * Author: Daniel Mårtensson 6 | */ 7 | 8 | #include "../Touch_screen.h" 9 | #include "../Hardware/ILI9341.h" 10 | #include "../../Functions.h" 11 | 12 | static uint8_t show_numpad_question(char title[], uint8_t *frame_id, uint8_t min_value, uint8_t max_value, uint8_t *value); 13 | 14 | void STM32_PLC_LCD_Show_Date_Time_Alarm_Settings_Frame(uint8_t *frame_id) { 15 | /* Clear the screen , but not the icons */ 16 | ILI9341_fill_rect(51, 6, 314, 234, COLOR_NAVY); 17 | 18 | /* Write the title */ 19 | ILI9341_draw_horizontal_line(50, 30, 265, COLOR_GREEN); 20 | ILI9341_print_text("Configure the date and time and alarm", 55, 10, COLOR_YELLOW, COLOR_NAVY, 1); 21 | 22 | /* Show the current date and time */ 23 | uint8_t year, month, week_day, date, hours, minutes, seconds; 24 | STM32_PLC_RTC_Get_Date(&date, &month, &year); 25 | STM32_PLC_RTC_Get_Time(&seconds, &minutes, &hours); 26 | char text[40]; 27 | ILI9341_print_text("Current date and time:", 55, 35, COLOR_YELLOW, COLOR_NAVY, 1); 28 | sprintf(text, "Date:%i-%i-%i Time:%i:%i:%i", year + 2000, month, date, hours, minutes, seconds); 29 | ILI9341_print_text(text, 55, 45, COLOR_YELLOW, COLOR_NAVY, 1); 30 | 31 | /* Print Alarm A */ 32 | bool active = STM32_PLC_RTC_Get_AlarmAB(RTC_ALARM_A, &minutes, &hours, &date, &week_day); 33 | ILI9341_print_text("Current alarm A:", 55, 55, COLOR_YELLOW, COLOR_NAVY, 1); 34 | sprintf(text, "Date:%i Time:%i:%i Active:%i", date, hours, minutes, active); 35 | ILI9341_print_text(text, 55, 65, COLOR_YELLOW, COLOR_NAVY, 1); 36 | 37 | /* Print Alarm B */ 38 | active = STM32_PLC_RTC_Get_AlarmAB(RTC_ALARM_B, &minutes, &hours, &date, &week_day); 39 | ILI9341_print_text("Current alarm B:", 55, 75, COLOR_YELLOW, COLOR_NAVY, 1); 40 | sprintf(text, "Week day:%i Time:%i:%i Active:%i", week_day, hours, minutes, active); 41 | ILI9341_print_text(text, 55, 85, COLOR_YELLOW, COLOR_NAVY, 1); 42 | 43 | /* Button */ 44 | ILI9341_fill_rect(65, 195, 300, 220, COLOR_GREEN); 45 | ILI9341_hollow_rect(65, 195, 300, 220, COLOR_BLACK); 46 | ILI9341_print_text("Set date time alarm", 70, 200, COLOR_BLACK, COLOR_GREEN, 2); 47 | 48 | /* Logic for button */ 49 | STM32_PLC_LCD_Call_One_Button_Logic(65, 195, 300, 220); 50 | 51 | /* Ask the user if */ 52 | if(STM32_PLC_LCD_Show_Question_Yes_No_Dialog("Do you want to set date and time?") == 0) { 53 | STM32_PLC_LCD_Show_Main_Frame(frame_id, false); 54 | return; 55 | } 56 | 57 | /* Enter date and time */ 58 | if(show_numpad_question("Enter year between 0 and 99", frame_id, 0, 99, &year)) 59 | return; 60 | if(show_numpad_question("Enter month between 1 and 12", frame_id, 1, 11, &month)) 61 | return; 62 | if(show_numpad_question("Enter week day between 1 and 7", frame_id, 1, 7, &week_day)) 63 | return; 64 | if(show_numpad_question("Enter date between 1 and 31", frame_id, 1, 31, &date)) 65 | return; 66 | if(show_numpad_question("Enter hours between 0 and 23", frame_id, 0, 23, &hours)) 67 | return; 68 | if(show_numpad_question("Enter minutes between 0 and 59", frame_id, 0, 59, &minutes)) 69 | return; 70 | 71 | /* Set date and time where seconds is 0 */ 72 | STM32_PLC_RTC_Set_Date(date, week_day, month, year); 73 | STM32_PLC_RTC_Set_Time(0, minutes, hours); 74 | 75 | /* Enter alarm A */ 76 | if(show_numpad_question("Alarm A:Enter hours between 0 and 23", frame_id, 0, 23, &hours)) 77 | return; 78 | if(show_numpad_question("Alarm A:Enter minutes between 0 and 59", frame_id, 0, 59, &minutes)) 79 | return; 80 | if(show_numpad_question("Alarm A:Enter date between 1 and 31", frame_id, 1, 31, &date)) 81 | return; 82 | 83 | /* Set alarm A */ 84 | STM32_PLC_RTC_Set_AlarmA(minutes, hours, date); 85 | 86 | /* Enter alarm B */ 87 | if(show_numpad_question("Alarm B:Enter hours between 0 and 23", frame_id, 0, 23, &hours)) 88 | return; 89 | if(show_numpad_question("Alarm B:Enter minutes between 0 and 59", frame_id, 0, 59, &minutes)) 90 | return; 91 | if(show_numpad_question("Alarm B:Enter week day between 1 and 7", frame_id, 1, 7, &week_day)) 92 | return; 93 | 94 | /* Set alarm B */ 95 | STM32_PLC_RTC_Set_AlarmB(minutes, hours, week_day); 96 | 97 | /* Exit */ 98 | STM32_PLC_LCD_Show_Main_Frame(frame_id, false); 99 | } 100 | 101 | static uint8_t show_numpad_question(char title[], uint8_t *frame_id, uint8_t min_value, uint8_t max_value, uint8_t *value){ 102 | bool minusbutton_show = false; 103 | bool decimalbutton_show = false; 104 | float number_value; 105 | if(STM32_PLC_LCD_Show_Numpad_Frame(decimalbutton_show, minusbutton_show, &number_value, title) == 0) { 106 | STM32_PLC_LCD_Show_Main_Frame(frame_id, false); 107 | return 1; 108 | } 109 | if(number_value < min_value) 110 | *value = min_value; 111 | else if(number_value > max_value) 112 | *value = max_value; 113 | else 114 | *value = (uint32_t) number_value; 115 | return 0; 116 | } 117 | -------------------------------------------------------------------------------- /Optimized ILI9341 Touch LCD/Touch Screen/Frames/PWM_frequency_settings_frame.c: -------------------------------------------------------------------------------- 1 | /* 2 | * PWM_frequency_settings_frame.c 3 | * 4 | * Created on: 25 juli 2021 5 | * Author: Daniel Mårtensson 6 | */ 7 | 8 | #include "../Touch_screen.h" 9 | #include "../Hardware/ILI9341.h" 10 | #include "../../Functions.h" 11 | 12 | static const uint16_t prescalers[20] = {0, 1, 2, 4, 6, 13, 72, 145, 182, 243, 365, 731, 1462, 2193, 2924, 3655, 4880, 7310, 65535}; 13 | 14 | void STM32_PLC_LCD_Show_PWM_Frequency_Settings_Frame(uint8_t *frame_id) { 15 | /* Clear the screen , but not the icons */ 16 | ILI9341_fill_rect(51, 6, 314, 234, COLOR_NAVY); 17 | 18 | /* Write the title */ 19 | ILI9341_draw_horizontal_line(50, 30, 265, COLOR_GREEN); 20 | ILI9341_print_text("Set PWM frequency", 55, 10, COLOR_YELLOW, COLOR_NAVY, 1); 21 | 22 | /* 23 | * For TIM2 and TIM5 24 | * Timer clock: 48 Mhz 25 | * Prescaler: Selected below 26 | * Counter: 65535 (0xffff) 27 | * Update frequency: See PWM choices 28 | * MATLAB formula: 29 | * for i = [0 1 2 4 6 13 72 145 182 243 365 731 1462 2193 2924 3655 4880 7310 65535] 30 | disp(sprintf("Hz = %i at prescaler = %i", (48*10^6/(1+i))/0xFFFF, i)); 31 | end 32 | */ 33 | 34 | /* Show all calibration inputs */ 35 | ILI9341_print_text("PWM choices to select:", 55, 35, COLOR_YELLOW, COLOR_NAVY, 1); 36 | ILI9341_print_text("732Hz=0 366Hz=1 244Hz=2", 55, 45, COLOR_YELLOW, COLOR_NAVY, 1); 37 | ILI9341_print_text("146Hz=4 104Hz=5 52Hz=6", 55, 55, COLOR_YELLOW, COLOR_NAVY, 1); 38 | ILI9341_print_text("10Hz=7 5Hz=8 4Hz=9", 55, 65, COLOR_YELLOW, COLOR_NAVY, 1); 39 | ILI9341_print_text("3Hz=10 2Hz=11 1Hz=12 0.5Hz=13", 55, 75, COLOR_YELLOW, COLOR_NAVY, 1); 40 | ILI9341_print_text("0.33Hz=14 0.25Hz=15 0.2Hz=16", 55, 85, COLOR_YELLOW, COLOR_NAVY, 1); 41 | ILI9341_print_text("0.15Hz=17 0.1Hz=18 0.011Hz=19", 55, 95, COLOR_YELLOW, COLOR_NAVY, 1); 42 | 43 | /* Show selected frequency */ 44 | if(STM32_PLC_SD_Mont_Card() != FR_OK){ 45 | STM32_PLC_LCD_Show_Information_OK_Dialog("Could not mount SD card"); 46 | STM32_PLC_LCD_Show_Main_Frame(frame_id, false); 47 | return; 48 | } 49 | STM32_PLC_SD_Open_Existing_File_With_Read("PWM.TXT"); 50 | char text[30]; 51 | STM32_PLC_SD_Read_File(text, sizeof(text)); 52 | STM32_PLC_SD_Close_File(); 53 | STM32_PLC_SD_Unmount_Card(); 54 | uint16_t prescaler_PWM_0_3 = atoi(strtok(text, DELIMITER)); 55 | uint16_t prescaler_PWM_4_7 = atoi(strtok(NULL, DELIMITER)); 56 | ILI9341_print_text("Current settings:", 55, 105, COLOR_YELLOW, COLOR_NAVY, 1); 57 | sprintf(text, "PWM_0_3:%i PWM_4_7:%i", prescaler_PWM_0_3, prescaler_PWM_4_7); 58 | ILI9341_print_text(text, 55, 105, COLOR_YELLOW, COLOR_NAVY, 1); 59 | 60 | /* Select settings button */ 61 | ILI9341_fill_rect(85, 195, 273, 220, COLOR_GREEN); 62 | ILI9341_hollow_rect(85, 195, 273, 220, COLOR_BLACK); 63 | ILI9341_print_text("Select PWM freq", 90, 200, COLOR_BLACK, COLOR_GREEN, 2); 64 | 65 | /* Logic for request button */ 66 | STM32_PLC_LCD_Call_One_Button_Logic(85, 195, 273, 220); 67 | 68 | /* Ask the user if */ 69 | if(STM32_PLC_LCD_Show_Question_Yes_No_Dialog("Do you want to set PWM frequency?") == 0) { 70 | STM32_PLC_LCD_Show_Main_Frame(frame_id, false); 71 | return; 72 | } 73 | 74 | /* You entered choice 1 - Show numpad */ 75 | bool minusbutton_show = false; 76 | bool decimalbutton_show = false; 77 | float number_value; 78 | if(STM32_PLC_LCD_Show_Numpad_Frame(decimalbutton_show, minusbutton_show, &number_value, "Enter input number between 0 and 19") == 0) { 79 | STM32_PLC_LCD_Show_Main_Frame(frame_id, false); 80 | return; 81 | } 82 | 83 | /* Check */ 84 | uint8_t PWM_frequency; 85 | if(number_value < 0) 86 | PWM_frequency = 0; 87 | else if(number_value > 19) 88 | PWM_frequency = 19; 89 | else 90 | PWM_frequency = (uint8_t) number_value; 91 | 92 | /* Ask for which PWM */ 93 | if(STM32_PLC_LCD_Show_Numpad_Frame(decimalbutton_show, minusbutton_show, &number_value, "Set setting for PWM0-PWM3=0 or PWM4-PWM7=1") == 0) { 94 | STM32_PLC_LCD_Show_Main_Frame(frame_id, false); 95 | return; 96 | } 97 | 98 | /* Check */ 99 | uint8_t PWM_TIM; 100 | if(number_value < 0) 101 | PWM_TIM = 0; 102 | else if(number_value > 1) 103 | PWM_TIM = 1; 104 | else 105 | PWM_TIM = (uint8_t) number_value; 106 | 107 | /* Apply them */ 108 | if(PWM_TIM == 0) 109 | STM32_PLC_PWM0_To_PWM3_Set_Prescaler(prescalers[PWM_frequency]); 110 | else 111 | STM32_PLC_PWM4_To_PWM7_Set_Prescaler(prescalers[PWM_frequency]); 112 | 113 | /* Mount */ 114 | if(STM32_PLC_SD_Mont_Card() != FR_OK){ 115 | STM32_PLC_LCD_Show_Information_OK_Dialog("Could not mount SD card"); 116 | STM32_PLC_LCD_Show_Main_Frame(frame_id, false); 117 | return; 118 | } 119 | 120 | /* Overwrite */ 121 | if(PWM_TIM == 0) 122 | prescaler_PWM_0_3 = PWM_frequency; 123 | else 124 | prescaler_PWM_4_7 = PWM_frequency; 125 | 126 | /* Write */ 127 | STM32_PLC_SD_Open_Existing_File_With_Write("PWM.TXT"); 128 | sprintf(text, "%i%s%i", prescaler_PWM_0_3, DELIMITER, prescaler_PWM_4_7); 129 | STM32_PLC_SD_Write_File(text); 130 | STM32_PLC_SD_Close_File(); 131 | STM32_PLC_SD_Unmount_Card(); 132 | STM32_PLC_LCD_Show_Main_Frame(frame_id, false); 133 | } 134 | -------------------------------------------------------------------------------- /ILI9341 Touch LCD/ReadMe.md: -------------------------------------------------------------------------------- 1 | # ILI9341 LCD with touch 2 | 3 | This is a simple LCD with touch feature. The communication protocol is SPI. The touch is not perfect for precision and speed, but at least you can display an image, press some large buttons and write a emoij. This LCD works perfect for simple use where you don't want physical buttons and instead want every button on your embedded system onto the LCD screen. 4 | 5 | This library contains 6 | - Windows 3.11 Question dialog 7 | - Icons 8 | - Start up screen 9 | - Plot with 2 graphs 10 | - Number pad 11 | - Frames etc. 12 | 13 | I recommend this LCD due to its price. 14 | 15 | Program example: 16 | 17 | ``` 18 | // Include 19 | #include "main.h" 20 | #include "LCD_ILI9341/LCDCore/LCD_ILI9341.h" 21 | #include "LCD_ILI9341/LCDTools/LCDTools.h" 22 | #include "stdbool.h" 23 | #include 24 | 25 | // Structure 26 | SPI_HandleTypeDef hspi2; 27 | ILI9341_SPI spi; 28 | 29 | int main(void) 30 | { 31 | // Init LCD 32 | // Init LCD 33 | ILI9341_Init(&spi, &hspi2, LCD_CS_GPIO_Port, LCD_CS_Pin, LCD_DC_GPIO_Port, LCD_DC_Pin, LCD_RST_GPIO_Port, LCD_RST_Pin, TS_CS_GPIO_Port, TS_CS_Pin); 34 | 35 | // Show welcome screen 36 | ILI9341_setRotation(&spi, 2); 37 | ILI9341_printImage(&spi, 0, 0, 320, 240, windows95_intro, 640*240*sizeof(uint8_t)); 38 | HAL_Delay(5000); 39 | 40 | // Calibrate the touch if blue Nucleo board button is pressed 41 | if (HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13) == GPIO_PIN_RESET) { 42 | TSC2046_Calibrate(&spi); 43 | } 44 | 45 | // Create initial frame 46 | show_main_frame(&spi, closedloop_on, update_main_frame, identification_on); 47 | 48 | // Create initial frame 49 | bool update_main_frame = true; 50 | bool decimalbutton_show = false; 51 | bool identification_on = false; 52 | bool minusbutton_show = false; 53 | bool closedloop_on = false; 54 | bool only_move_array = false; 55 | bool clear_plot = false; 56 | bool stable = true; 57 | bool hasChangedStability = true; 58 | float number_value = 0.0; 59 | int16_t status; 60 | create_main_frame(&spi, closedloop_on, only_change_loop_icon); 61 | 62 | while (1) { 63 | // Read the LCD touch 64 | TSC2046_GetTouchData(&spi); 65 | uint8_t isPressed = spi.myTsData.isPressed; 66 | uint16_t X = spi.myTsData.X; 67 | uint16_t Y = spi.myTsData.Y; 68 | if (isPressed == true) { 69 | // Check which button we are pressing on 70 | if (X >= 8 && X <= 37 && Y >= 8 && Y <= 37) { 71 | // Set point 72 | decimalbutton_show = true; 73 | minusbutton_show = false; 74 | show_num_pad_frame(&spi, decimalbutton_show, minusbutton_show, &setpoint, "Set setpoint <= 100"); 75 | if (setpoint > 100) 76 | setpoint = 100; 77 | update_main_frame = true; 78 | show_main_frame(&spi, closedloop_on, update_main_frame, identification_on); 79 | } else if (X >= 8 && X <= 37 && Y >= 55 && Y <= 94) { 80 | // Set horizon 81 | decimalbutton_show = false; 82 | minusbutton_show = false; 83 | show_num_pad_frame(&spi, decimalbutton_show, minusbutton_show, &horizon, "Set horizon"); 84 | update_main_frame = true; 85 | show_main_frame(&spi, closedloop_on, update_main_frame, identification_on); 86 | htim3.Instance->CCR1 = (uint32_t) horizon; 87 | } else if (X >= 8 && X <= 37 && Y >= 100 && Y <= 139) { 88 | // Identification on or off 89 | if(identification_on == true) 90 | identification_on = false; 91 | else 92 | identification_on = true; 93 | update_main_frame = false; 94 | osDelay(300); // Prevent double click 95 | show_main_frame(&spi, closedloop_on, update_main_frame, identification_on); 96 | } else if (X >= 8 && X <= 37 && Y >= 146 && Y <= 185) { 97 | // Open loop or closed loop 98 | if (closedloop_on == true) 99 | closedloop_on = false; 100 | else 101 | closedloop_on = true; 102 | update_main_frame = false; 103 | osDelay(300); // Prevent double click 104 | show_main_frame(&spi, closedloop_on, update_main_frame, identification_on); 105 | } else if (X >= 8 && X <= 37 && Y >= 193 && Y <= 232) { 106 | // Question dialog 107 | uint8_t choice = show_question_save_settings_dialog(&spi); // Return 1 as YES and 0 as NO 108 | if (choice == 1) { 109 | // Save the touch calibration and the user settings 110 | float wrBuf[7] = { spi.myTS_Calibrate.Scale_X, spi.myTS_Calibrate.Scale_Y, spi.myTS_Calibrate.Bias_X, spi.myTS_Calibrate.Bias_Y, setpoint, horizon, forgetting }; 111 | FlashEraseSector(); // Must clear first 112 | FlashWriteN(0, wrBuf, 7, DATA_TYPE_FLOAT); 113 | } 114 | 115 | // Restore to normal again 116 | update_main_frame = true; 117 | show_main_frame(&spi, closedloop_on, update_main_frame, identification_on); 118 | } 119 | // For every time we change back to main screen, print out if our model is table or not 120 | displayStableOrUnstable(); 121 | } else { 122 | // Maximum plot can show is value 203 123 | uint16_t new_output_uint = 2 * ((uint16_t) new_output_float); 124 | uint16_t new_input_uint = 2 * ((uint16_t) new_input_float); 125 | show_plot_frame(&spi, new_input_float, new_output_float, new_input_uint, new_output_uint, only_move_array, clear_plot); 126 | } 127 | } 128 | } 129 | ``` 130 | -------------------------------------------------------------------------------- /ILI9341 Touch LCD/LCDTools/printf.h: -------------------------------------------------------------------------------- 1 | /* 2 | * printf.h 3 | * 4 | * Created on: May 24, 2020 5 | * Author: Daniel Mårtensson 6 | */ 7 | 8 | #ifndef SRC_LCD_ILI9341_LCDTOOLS_PRINTF_H_ 9 | #define SRC_LCD_ILI9341_LCDTOOLS_PRINTF_H_ 10 | 11 | /////////////////////////////////////////////////////////////////////////////// 12 | // \author (c) Marco Paland (info@paland.com) 13 | // 2014-2019, PALANDesign Hannover, Germany 14 | // 15 | // \license The MIT License (MIT) 16 | // 17 | // Permission is hereby granted, free of charge, to any person obtaining a copy 18 | // of this software and associated documentation files (the "Software"), to deal 19 | // in the Software without restriction, including without limitation the rights 20 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 21 | // copies of the Software, and to permit persons to whom the Software is 22 | // furnished to do so, subject to the following conditions: 23 | // 24 | // The above copyright notice and this permission notice shall be included in 25 | // all copies or substantial portions of the Software. 26 | // 27 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 28 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 29 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 30 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 31 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 32 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 33 | // THE SOFTWARE. 34 | // 35 | // \brief Tiny printf, sprintf and snprintf implementation, optimized for speed on 36 | // embedded systems with a very limited resources. 37 | // Use this instead of bloated standard/newlib printf. 38 | // These routines are thread safe and reentrant. 39 | // 40 | /////////////////////////////////////////////////////////////////////////////// 41 | 42 | #ifndef _PRINTF_H_ 43 | #define _PRINTF_H_ 44 | 45 | #include 46 | #include 47 | 48 | 49 | #ifdef __cplusplus 50 | extern "C" { 51 | #endif 52 | 53 | 54 | /** 55 | * Output a character to a custom device like UART, used by the printf() function 56 | * This function is declared here only. You have to write your custom implementation somewhere 57 | * \param character Character to output 58 | */ 59 | void _putchar(char character); 60 | 61 | 62 | /** 63 | * Tiny printf implementation 64 | * You have to implement _putchar if you use printf() 65 | * To avoid conflicts with the regular printf() API it is overridden by macro defines 66 | * and internal underscore-appended functions like printf_() are used 67 | * \param format A string that specifies the format of the output 68 | * \return The number of characters that are written into the array, not counting the terminating null character 69 | */ 70 | #define printf printf_ 71 | int printf_(const char* format, ...); 72 | 73 | 74 | /** 75 | * Tiny sprintf implementation 76 | * Due to security reasons (buffer overflow) YOU SHOULD CONSIDER USING (V)SNPRINTF INSTEAD! 77 | * \param buffer A pointer to the buffer where to store the formatted string. MUST be big enough to store the output! 78 | * \param format A string that specifies the format of the output 79 | * \return The number of characters that are WRITTEN into the buffer, not counting the terminating null character 80 | */ 81 | #define sprintf sprintf_ 82 | int sprintf_(char* buffer, const char* format, ...); 83 | 84 | 85 | /** 86 | * Tiny snprintf/vsnprintf implementation 87 | * \param buffer A pointer to the buffer where to store the formatted string 88 | * \param count The maximum number of characters to store in the buffer, including a terminating null character 89 | * \param format A string that specifies the format of the output 90 | * \param va A value identifying a variable arguments list 91 | * \return The number of characters that COULD have been written into the buffer, not counting the terminating 92 | * null character. A value equal or larger than count indicates truncation. Only when the returned value 93 | * is non-negative and less than count, the string has been completely written. 94 | */ 95 | #define snprintf snprintf_ 96 | #define vsnprintf vsnprintf_ 97 | int snprintf_(char* buffer, size_t count, const char* format, ...); 98 | int vsnprintf_(char* buffer, size_t count, const char* format, va_list va); 99 | 100 | 101 | /** 102 | * Tiny vprintf implementation 103 | * \param format A string that specifies the format of the output 104 | * \param va A value identifying a variable arguments list 105 | * \return The number of characters that are WRITTEN into the buffer, not counting the terminating null character 106 | */ 107 | #define vprintf vprintf_ 108 | int vprintf_(const char* format, va_list va); 109 | 110 | 111 | /** 112 | * printf with output function 113 | * You may use this as dynamic alternative to printf() with its fixed _putchar() output 114 | * \param out An output function which takes one character and an argument pointer 115 | * \param arg An argument pointer for user data passed to output function 116 | * \param format A string that specifies the format of the output 117 | * \return The number of characters that are sent to the output function, not counting the terminating null character 118 | */ 119 | int fctprintf(void (*out)(char character, void* arg), void* arg, const char* format, ...); 120 | 121 | 122 | #ifdef __cplusplus 123 | } 124 | #endif 125 | 126 | 127 | #endif // _PRINTF_H_ 128 | 129 | 130 | #endif /* SRC_LCD_ILI9341_LCDTOOLS_PRINTF_H_ */ 131 | -------------------------------------------------------------------------------- /Micro SD SPI/user_diskio.c: -------------------------------------------------------------------------------- 1 | /* USER CODE BEGIN Header */ 2 | /** 3 | ****************************************************************************** 4 | * @file user_diskio.c 5 | * @brief This file includes a diskio driver skeleton to be completed by the user. 6 | ****************************************************************************** 7 | * @attention 8 | * 9 | *

© Copyright (c) 2020 STMicroelectronics. 10 | * All rights reserved.

11 | * 12 | * This software component is licensed by ST under Ultimate Liberty license 13 | * SLA0044, the "License"; You may not use this file except in compliance with 14 | * the License. You may obtain a copy of the License at: 15 | * www.st.com/SLA0044 16 | * 17 | ****************************************************************************** 18 | */ 19 | /* USER CODE END Header */ 20 | 21 | #ifdef USE_OBSOLETE_USER_CODE_SECTION_0 22 | /* 23 | * Warning: the user section 0 is no more in use (starting from CubeMx version 4.16.0) 24 | * To be suppressed in the future. 25 | * Kept to ensure backward compatibility with previous CubeMx versions when 26 | * migrating projects. 27 | * User code previously added there should be copied in the new user sections before 28 | * the section contents can be deleted. 29 | */ 30 | /* USER CODE BEGIN 0 */ 31 | /* USER CODE END 0 */ 32 | #endif 33 | 34 | /* USER CODE BEGIN DECL */ 35 | 36 | /* Includes ------------------------------------------------------------------*/ 37 | #include 38 | #include "ff_gen_drv.h" 39 | 40 | /* Private typedef -----------------------------------------------------------*/ 41 | /* Private define ------------------------------------------------------------*/ 42 | #include "../Src/Micro SD SPI/fatfs_sd.h" 43 | /* Private variables ---------------------------------------------------------*/ 44 | /* Disk status */ 45 | static volatile DSTATUS Stat = STA_NOINIT; 46 | 47 | /* USER CODE END DECL */ 48 | 49 | /* Private function prototypes -----------------------------------------------*/ 50 | DSTATUS USER_initialize (BYTE pdrv); 51 | DSTATUS USER_status (BYTE pdrv); 52 | DRESULT USER_read (BYTE pdrv, BYTE *buff, DWORD sector, UINT count); 53 | #if _USE_WRITE == 1 54 | DRESULT USER_write (BYTE pdrv, const BYTE *buff, DWORD sector, UINT count); 55 | #endif /* _USE_WRITE == 1 */ 56 | #if _USE_IOCTL == 1 57 | DRESULT USER_ioctl (BYTE pdrv, BYTE cmd, void *buff); 58 | #endif /* _USE_IOCTL == 1 */ 59 | 60 | Diskio_drvTypeDef USER_Driver = 61 | { 62 | USER_initialize, 63 | USER_status, 64 | USER_read, 65 | #if _USE_WRITE 66 | USER_write, 67 | #endif /* _USE_WRITE == 1 */ 68 | #if _USE_IOCTL == 1 69 | USER_ioctl, 70 | #endif /* _USE_IOCTL == 1 */ 71 | }; 72 | 73 | /* Private functions ---------------------------------------------------------*/ 74 | 75 | /** 76 | * @brief Initializes a Drive 77 | * @param pdrv: Physical drive number (0..) 78 | * @retval DSTATUS: Operation status 79 | */ 80 | DSTATUS USER_initialize ( 81 | BYTE pdrv /* Physical drive nmuber to identify the drive */ 82 | ) 83 | { 84 | /* USER CODE BEGIN INIT */ 85 | return SD_disk_initialize(pdrv); 86 | /* USER CODE END INIT */ 87 | } 88 | 89 | /** 90 | * @brief Gets Disk Status 91 | * @param pdrv: Physical drive number (0..) 92 | * @retval DSTATUS: Operation status 93 | */ 94 | DSTATUS USER_status ( 95 | BYTE pdrv /* Physical drive number to identify the drive */ 96 | ) 97 | { 98 | /* USER CODE BEGIN STATUS */ 99 | return SD_disk_status(pdrv); 100 | /* USER CODE END STATUS */ 101 | } 102 | 103 | /** 104 | * @brief Reads Sector(s) 105 | * @param pdrv: Physical drive number (0..) 106 | * @param *buff: Data buffer to store read data 107 | * @param sector: Sector address (LBA) 108 | * @param count: Number of sectors to read (1..128) 109 | * @retval DRESULT: Operation result 110 | */ 111 | DRESULT USER_read ( 112 | BYTE pdrv, /* Physical drive nmuber to identify the drive */ 113 | BYTE *buff, /* Data buffer to store read data */ 114 | DWORD sector, /* Sector address in LBA */ 115 | UINT count /* Number of sectors to read */ 116 | ) 117 | { 118 | /* USER CODE BEGIN READ */ 119 | return SD_disk_read(pdrv, buff, sector, count); 120 | /* USER CODE END READ */ 121 | } 122 | 123 | /** 124 | * @brief Writes Sector(s) 125 | * @param pdrv: Physical drive number (0..) 126 | * @param *buff: Data to be written 127 | * @param sector: Sector address (LBA) 128 | * @param count: Number of sectors to write (1..128) 129 | * @retval DRESULT: Operation result 130 | */ 131 | #if _USE_WRITE == 1 132 | DRESULT USER_write ( 133 | BYTE pdrv, /* Physical drive nmuber to identify the drive */ 134 | const BYTE *buff, /* Data to be written */ 135 | DWORD sector, /* Sector address in LBA */ 136 | UINT count /* Number of sectors to write */ 137 | ) 138 | { 139 | /* USER CODE BEGIN WRITE */ 140 | /* USER CODE HERE */ 141 | return SD_disk_write(pdrv, buff, sector, count); 142 | /* USER CODE END WRITE */ 143 | } 144 | #endif /* _USE_WRITE == 1 */ 145 | 146 | /** 147 | * @brief I/O control operation 148 | * @param pdrv: Physical drive number (0..) 149 | * @param cmd: Control code 150 | * @param *buff: Buffer to send/receive control data 151 | * @retval DRESULT: Operation result 152 | */ 153 | #if _USE_IOCTL == 1 154 | DRESULT USER_ioctl ( 155 | BYTE pdrv, /* Physical drive nmuber (0..) */ 156 | BYTE cmd, /* Control code */ 157 | void *buff /* Buffer to send/receive control data */ 158 | ) 159 | { 160 | /* USER CODE BEGIN IOCTL */ 161 | return SD_disk_ioctl(pdrv, cmd, buff); 162 | /* USER CODE END IOCTL */ 163 | } 164 | #endif /* _USE_IOCTL == 1 */ 165 | 166 | /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ 167 | -------------------------------------------------------------------------------- /HX711 Load Cell Amplifier/HX711.c: -------------------------------------------------------------------------------- 1 | /* 2 | * HX711.c 3 | * 4 | * Created on: Jun 6, 2020 5 | * Author: Daniel Mårtensson 6 | */ 7 | 8 | #include "HX711.h" 9 | 10 | // Make shiftIn() be aware of clockspeed for 11 | // faster CPUs like ESP32, Teensy 3.x and friends. 12 | // See also: 13 | // - https://github.com/bogde/HX711/issues/75 14 | // - https://github.com/arduino/Arduino/issues/6561 15 | // - https://community.hiveeyes.org/t/using-bogdans-canonical-hx711-library-on-the-esp32/539 16 | static uint8_t shiftIn(HX711 *hx, uint8_t bitOrder) { 17 | uint8_t value = 0; 18 | uint8_t i; 19 | 20 | for (i = 0; i < 8; ++i) { 21 | HAL_GPIO_WritePin(hx->PD_SCK_Port, hx->PD_SCK_Pin, GPIO_PIN_SET); 22 | for (uint16_t i = 0; i < SMALL_DELAY; i++) {} // Small delay 23 | if (bitOrder == LSBFIRST) 24 | value |= HAL_GPIO_ReadPin(hx->DOUT_Port, hx->DOUT_Pin) << i; 25 | else 26 | value |= HAL_GPIO_ReadPin(hx->DOUT_Port, hx->DOUT_Pin) << (7 - i); 27 | HAL_GPIO_WritePin(hx->PD_SCK_Port, hx->PD_SCK_Pin, GPIO_PIN_RESET); 28 | for (uint16_t i = 0; i < SMALL_DELAY; i++) {} // Small delay 29 | } 30 | return value; 31 | } 32 | 33 | void HX711_begin(HX711 *hx, GPIO_TypeDef* PD_SCK_Port, uint16_t PD_SCK_Pin, GPIO_TypeDef* DOUT_Port, uint16_t DOUT_Pin, uint8_t gain) { 34 | // Digital output 35 | hx->PD_SCK_Port = PD_SCK_Port; 36 | hx->PD_SCK_Pin = PD_SCK_Pin; 37 | // Digital pull-up input 38 | hx->DOUT_Port = DOUT_Port; 39 | hx->DOUT_Pin = DOUT_Pin; 40 | // Set gain 41 | HX711_set_gain(hx, gain); 42 | } 43 | 44 | bool HX711_is_ready(HX711 *hx) { 45 | return !HAL_GPIO_ReadPin(hx->DOUT_Port, hx->DOUT_Pin); 46 | } 47 | 48 | void HX711_set_gain(HX711 *hx, uint8_t gain) { 49 | switch (gain) { 50 | case 128: // channel A, gain factor 128 51 | hx->GAIN = 1; 52 | break; 53 | case 64: // channel A, gain factor 64 54 | hx->GAIN = 3; 55 | break; 56 | case 32: // channel B, gain factor 32 57 | hx->GAIN = 2; 58 | break; 59 | } 60 | } 61 | 62 | long HX711_read(HX711 *hx) { 63 | 64 | // Wait for the chip to become ready. 65 | HX711_wait_ready(hx, 0); 66 | 67 | // Define structures for reading data into. 68 | unsigned long value = 0; 69 | uint8_t data[3] = { 0 }; 70 | uint8_t filler = 0x00; 71 | 72 | // Pulse the clock pin 24 times to read the data. 73 | data[2] = shiftIn(hx, MSBFIRST); 74 | data[1] = shiftIn(hx, MSBFIRST); 75 | data[0] = shiftIn(hx, MSBFIRST); 76 | 77 | // Set the channel and the gain factor for the next reading using the clock pin. 78 | for (unsigned int i = 0; i < hx->GAIN; i++) { 79 | HAL_GPIO_WritePin(hx->PD_SCK_Port, hx->PD_SCK_Pin, GPIO_PIN_SET); 80 | for (uint16_t i = 0; i < SMALL_DELAY; i++) {} // Small delay 81 | HAL_GPIO_WritePin(hx->PD_SCK_Port, hx->PD_SCK_Pin, GPIO_PIN_RESET); 82 | for (uint16_t i = 0; i < SMALL_DELAY; i++) { } // Small delay 83 | } 84 | 85 | // Replicate the most significant bit to pad out a 32-bit signed integer 86 | if (data[2] & 0x80) { 87 | filler = 0xFF; 88 | } else { 89 | filler = 0x00; 90 | } 91 | 92 | // Construct a 32-bit signed integer 93 | value = (unsigned long) (filler << 24) 94 | | (unsigned long) (data[2] << 16) 95 | | (unsigned long) (data[1] << 8) 96 | | (unsigned long) (data[0]); 97 | 98 | return (long) value; 99 | } 100 | 101 | void HX711_wait_ready(HX711 *hx, unsigned long delay_ms) { 102 | // Wait for the chip to become ready. 103 | // This is a blocking implementation and will 104 | // halt the sketch until a load cell is connected. 105 | while (!HX711_is_ready(hx)) { 106 | // Probably will do no harm on AVR but will feed the Watchdog Timer (WDT) on ESP. 107 | // https://github.com/bogde/HX711/issues/73 108 | HAL_Delay(delay_ms); 109 | } 110 | } 111 | 112 | bool HX711_wait_ready_retry(HX711 *hx, int retries, unsigned long delay_ms) { 113 | // Wait for the chip to become ready by 114 | // retrying for a specified amount of attempts. 115 | // https://github.com/bogde/HX711/issues/76 116 | int count = 0; 117 | while (count < retries) { 118 | if (HX711_is_ready(hx)) { 119 | return true; 120 | } 121 | HAL_Delay(delay_ms); 122 | count++; 123 | } 124 | return false; 125 | } 126 | 127 | bool HX711_wait_ready_timeout(HX711 *hx, unsigned long timeout, unsigned long delay_ms) { 128 | // Wait for the chip to become ready until timeout. 129 | // https://github.com/bogde/HX711/pull/96 130 | unsigned long millisStarted = HAL_GetTick(); 131 | while (HAL_GetTick() - millisStarted < timeout) { 132 | if (HX711_is_ready(hx)) { 133 | return true; 134 | } 135 | HAL_Delay(delay_ms); 136 | } 137 | return false; 138 | } 139 | 140 | long HX711_read_average(HX711 *hx, uint8_t times) { 141 | long sum = 0; 142 | for (uint8_t i = 0; i < times; i++) { 143 | sum += HX711_read(hx); 144 | // Probably will do no harm on AVR but will feed the Watchdog Timer (WDT) on ESP. 145 | // https://github.com/bogde/HX711/issues/73 146 | HAL_Delay(0); 147 | } 148 | return sum / times; 149 | } 150 | 151 | float HX711_get_value(HX711 *hx, uint8_t times) { 152 | return HX711_read_average(hx, times) - hx->OFFSET; 153 | } 154 | 155 | float HX711_get_units(HX711 *hx, uint8_t times) { 156 | return HX711_get_value(hx, times) / hx->SCALE; 157 | } 158 | 159 | void HX711_tare(HX711 *hx, uint8_t times) { 160 | float sum = HX711_read_average(hx, times); 161 | HX711_set_offset(hx, sum); 162 | } 163 | 164 | void HX711_set_scale(HX711 *hx, float scale) { 165 | hx->SCALE = scale; 166 | } 167 | 168 | float HX711_get_scale(HX711 *hx) { 169 | return hx->SCALE; 170 | } 171 | 172 | void HX711_set_offset(HX711 *hx, long offset) { 173 | hx->OFFSET = offset; 174 | } 175 | 176 | long HX711_get_offset(HX711 *hx) { 177 | return hx->OFFSET; 178 | } 179 | 180 | void HX711_power_down(HX711 *hx) { 181 | HAL_GPIO_WritePin(hx->PD_SCK_Port, hx->PD_SCK_Pin, GPIO_PIN_RESET); 182 | HAL_GPIO_WritePin(hx->PD_SCK_Port, hx->PD_SCK_Pin, GPIO_PIN_SET); 183 | } 184 | 185 | void HX711_power_up(HX711 *hx) { 186 | HAL_GPIO_WritePin(hx->PD_SCK_Port, hx->PD_SCK_Pin, GPIO_PIN_RESET); 187 | } 188 | -------------------------------------------------------------------------------- /Optimized ILI9341 Touch LCD/ReadMe.md: -------------------------------------------------------------------------------- 1 | # Optimized ILI9341 LCD with touch 2 | 3 | This is a simple library who is optimized for touch and screen. What I have done is that I had made a project that don't use threads and therefore I have optimized this 4 | LCD library so it can write out images very fast using only two SPI. One SPI for the touch and one SPI for the LCD. 5 | 6 | This is just examples. Just copy the code and modify it after your own choice. 7 | 8 | Example: 9 | 10 | ```c 11 | /* Create structure, the J1939 structure is from another project called Open SAE J1939 at my Github */ 12 | J1939 j1939 = {0}; 13 | STM32_PLC stm32_plc = {0}; 14 | 15 | /* Init */ 16 | STM32_PLC_LCD(&hspi1, &hspi2, LCD_CS_GPIO_Port, LCD_CS_Pin, LCD_DC_GPIO_Port, LCD_DC_Pin, LCD_RST_GPIO_Port, LCD_RST_Pin, TS_CS_GPIO_Port, TS_CS_Pin); 17 | 18 | /* Introduction startup */ 19 | STM32_PLC_LCD_Show_Intro_Frame(); 20 | 21 | /* Introduction startup */ 22 | STM32_PLC_LCD_Show_Intro_Frame(); 23 | 24 | /* Check if we touch at the screen */ 25 | if(STM32_PLC_LCD_Is_Pressed()){ 26 | /* Blink with all LED lamps before calibration start */ 27 | for(uint8_t i = 0; i < 3; i++){ 28 | STM32_PLC_LCD_Set_Control_Program(0x1F); 29 | HAL_Delay(1000); 30 | STM32_PLC_LCD_Set_Control_Program(0x0); 31 | HAL_Delay(1000); 32 | } 33 | STM32_PLC_LCD_Set_Control_Program(stm32_plc.program_number); 34 | STM32_PLC_LCD_Calibrate_Touch(); 35 | STM32_PLC_LCD_Get_Touch_Calibration_Parameters(&stm32_plc.Scale_X, &stm32_plc.Scale_Y, &stm32_plc.Bias_X, &stm32_plc.Bias_Y); 36 | if(!Save_Struct((uint8_t*)&stm32_plc, sizeof(STM32_PLC), STM32_PLC_TEXT_FILE_NAME)) 37 | STM32_PLC_LCD_Show_Information_OK_Dialog("Could not mount SD card"); 38 | } 39 | 40 | /* Frame start */ 41 | uint8_t frame_id = 0; 42 | STM32_PLC_LCD_Show_Main_Frame(&frame_id, false); 43 | 44 | while (1) 45 | { 46 | /* USER CODE END WHILE */ 47 | 48 | /* USER CODE BEGIN 3 */ 49 | 50 | /* Listen for frame changes */ 51 | STM32_PLC_LCD_Call_Main_Logic(&frame_id, &j1939, &stm32_plc); 52 | /* Perform control program */ 53 | STM32_PLC_LCD_Execute_Control_Program(&j1939); 54 | 55 | } 56 | 57 | ``` 58 | 59 | Functionality: 60 | 61 | ```c 62 | void STM32_PLC_Start_LCD(SPI_HandleTypeDef *lcdSpi, SPI_HandleTypeDef *touchSpi, GPIO_TypeDef *LCD_CS_PORT, uint16_t LCD_CS_PIN, GPIO_TypeDef *LCD_DC_PORT, uint16_t LCD_DC_PIN, GPIO_TypeDef *LCD_RESET_PORT, uint16_t LCD_RESET_PIN, GPIO_TypeDef *TOUCH_CS_PORT, uint16_t TOUCH_CS_PIN); 63 | void STM32_PLC_LCD_Calibrate_Touch(); 64 | void STM32_PLC_LCD_Get_Touch_Calibration_Parameters(float *Scale_X, float *Scale_Y, float *Bias_X, float *Bias_Y); 65 | void STM32_PLC_LCD_Set_Touch_Calibration_Parameters(float *Scale_X, float *Scale_Y, float *Bias_X, float *Bias_Y); 66 | void STM32_PLC_LCD_Get_Touch_Data(); 67 | 68 | 69 | /* Frames with no frame id */ 70 | void STM32_PLC_LCD_Show_Intro_Frame(); 71 | void STM32_PLC_LCD_Show_Main_Frame(uint8_t *frame_id, bool change_only_ABC_buttons); 72 | uint8_t STM32_PLC_LCD_Show_Numpad_Frame(bool decimalbutton_show, bool minusbutton_show, float *number_value, char title[]); 73 | uint8_t STM32_PLC_LCD_Show_Keyboard_Frame(char word[], char title[]); 74 | void STM32_PLC_LCD_Show_Plot_Frame(); 75 | 76 | /* Frame id 0 */ 77 | void STM32_PLC_LCD_Show_Measurement_And_Time_Frame(uint8_t *frame_id); 78 | void STM32_PLC_LCD_Show_Analog_Calibration_Frame(uint8_t *frame_id, STM32_PLC* stm32_plc); 79 | void STM32_PLC_LCD_Show_PWM_Frequency_Settings_Frame(uint8_t *frame_id, STM32_PLC* stm32_plc); 80 | 81 | /* Frame id 1 */ 82 | void STM32_PLC_LCD_Show_Logging_Frame(J1939 *j1939, uint8_t *frame_id); 83 | void STM32_PLC_LCD_Show_Control_Program_Settings_Frame(uint8_t *frame_id, STM32_PLC* stm32_plc); 84 | void STM32_PLC_LCD_Show_Date_Time_Alarm_Settings_Frame(uint8_t *frame_id); 85 | 86 | /* Frame id 2 */ 87 | void STM32_PLC_LCD_Show_SAE_J1939_Request_Frame(J1939 *j1939, uint8_t *frame_id); 88 | void STM32_PLC_LCD_Show_SAE_J1939_Address_Frame(J1939 *j1939, uint8_t *frame_id); 89 | void STM32_PLC_LCD_Show_SAE_J1939_Commanded_Address_Frame(J1939 *j1939, uint8_t *frame_id); 90 | 91 | /* Frame id 3 */ 92 | void STM32_PLC_LCD_Show_SAE_J1939_This_ECU_DM1_Frame(J1939 *j1939, uint8_t *frame_id); 93 | void STM32_PLC_LCD_Show_SAE_J1939_Other_ECU_DM1_Frame(J1939 *j1939, uint8_t *frame_id); 94 | void STM32_PLC_LCD_Show_SAE_J1939_This_ECU_DM2_Frame(J1939 *j1939, uint8_t *frame_id); 95 | 96 | /* Frame id 4 */ 97 | void STM32_PLC_LCD_Show_SAE_J1939_Other_ECU_DM2_Frame(J1939 *j1939, uint8_t *frame_id); 98 | void STM32_PLC_LCD_Show_SAE_J1939_This_ECU_Name_Frame(J1939 *j1939, uint8_t *frame_id); 99 | void STM32_PLC_LCD_Show_SAE_J1939_Other_ECU_Name_Frame(J1939 *j1939, uint8_t *frame_id); 100 | 101 | /* Frame id 5 */ 102 | void STM32_PLC_LCD_Show_SAE_J1939_This_ECU_Identifications_Frame(J1939 *j1939, uint8_t *frame_id); 103 | void STM32_PLC_LCD_Show_SAE_J1939_Other_ECU_Identifications_Frame(J1939 *j1939, uint8_t *frame_id); 104 | void STM32_PLC_LCD_Show_Encoder_Revolutions_Settings_Frame(uint8_t *frame_id, STM32_PLC* stm32_plc); 105 | 106 | /* Frame id 6 */ 107 | void STM32_PLC_LCD_Show_SDADC_Settings_Frame(uint8_t *frame_id, STM32_PLC* stm32_plc); 108 | 109 | /* Dialogs */ 110 | uint8_t STM32_PLC_LCD_Show_Question_Yes_No_Dialog(char question[]); 111 | uint8_t STM32_PLC_LCD_Show_Information_OK_Dialog(char information[]); 112 | 113 | /* Logics */ 114 | void STM32_PLC_LCD_Call_Main_Logic(uint8_t *frame_id, J1939 *j1939, STM32_PLC* stm32_plc); 115 | uint8_t STM32_PLC_LCD_Call_Numpad_Logic(bool decimalbutton_show, bool minusbutton_show, float *number_value); 116 | uint8_t STM32_PLC_LCD_Call_Keyboard_Logic(char word[]); 117 | uint8_t STM32_PLC_LCD_Call_Two_Button_Logic(uint16_t b1_x1, uint16_t b1_y1, uint16_t b1_x2, uint16_t b1_y2, uint16_t b2_x1, uint16_t b2_y1, uint16_t b2_x2, uint16_t b2_y2); 118 | uint8_t STM32_PLC_LCD_Call_One_Button_Logic(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2); 119 | 120 | /* Automatic Control Program */ 121 | void STM32_PLC_LCD_Set_Control_Program(uint8_t program_number); 122 | void STM32_PLC_LCD_Set_Program_Parameters(float parameters[]); 123 | uint8_t STM32_PLC_LCD_Get_Control_Program(); 124 | void STM32_PLC_LCD_Execute_Control_Program(J1939 *j1939); 125 | ``` 126 | -------------------------------------------------------------------------------- /PCA9685 PWM Servo/PCA9685.c: -------------------------------------------------------------------------------- 1 | /* 2 | * PCA9685.c 3 | * 4 | * Created on: Jun 6, 2020 5 | * Author: Daniel Mårtensson 6 | */ 7 | 8 | #include "../PCA9685 PWM Servo/PCA9685.h" 9 | 10 | static uint8_t read8(PCA9685_I2C *i2c, uint8_t addr) { 11 | uint8_t pData[] = { addr }; 12 | if(HAL_I2C_Master_Transmit(i2c->hi2c, i2c->address, pData, 1, 10) != HAL_OK) 13 | return 0; 14 | if(HAL_I2C_Master_Receive(i2c->hi2c, i2c->address, pData, 1, 10) != HAL_OK) 15 | return 0; 16 | 17 | return pData[0]; 18 | } 19 | 20 | static void write8(PCA9685_I2C *i2c, uint8_t addr, uint8_t d) { 21 | uint8_t pData[2] = { addr, d }; 22 | if(HAL_I2C_Master_Transmit(i2c->hi2c, i2c->address, pData, 2, 10) != HAL_OK) 23 | return; // For debugging tool in STM 24 | } 25 | 26 | void PCA9685_setOscillatorFrequency(PCA9685_I2C *i2c, uint32_t freq) { 27 | i2c->oscillator_freq = freq; 28 | } 29 | 30 | uint32_t PCA9685_getOscillatorFrequency(PCA9685_I2C *i2c) { 31 | return i2c->oscillator_freq; 32 | } 33 | 34 | void PCA9685_writeMicroseconds(PCA9685_I2C *i2c, uint8_t num, uint16_t Microseconds) { 35 | float pulse = Microseconds; 36 | float pulselength = 1000000; // 1,000,000 us per second 37 | 38 | // Read prescale 39 | uint16_t prescale = PCA9685_readPrescale(i2c); 40 | 41 | // Calculate the pulse for PWM based on Equation 1 from the datasheet section 42 | // 7.3.5 43 | prescale += 1; 44 | pulselength *= prescale; 45 | pulselength /= i2c->oscillator_freq; 46 | pulse /= pulselength; 47 | PCA9685_setPWM(i2c, num, 0, pulse); 48 | } 49 | 50 | void PCA9685_setPin(PCA9685_I2C *i2c, uint8_t num, uint16_t val, bool invert) { 51 | // Clamp value between 0 and 4095 inclusive. 52 | if(val > 4095) 53 | val = 4095; 54 | if (invert) { 55 | if (val == 0) { 56 | // Special value for signal fully on. 57 | PCA9685_setPWM(i2c, num, 4096, 0); 58 | } else if (val == 4095) { 59 | // Special value for signal fully off. 60 | PCA9685_setPWM(i2c, num, 0, 4096); 61 | } else { 62 | PCA9685_setPWM(i2c, num, 0, 4095 - val); 63 | } 64 | } else { 65 | if (val == 4095) { 66 | // Special value for signal fully on. 67 | PCA9685_setPWM(i2c, num, 4096, 0); 68 | } else if (val == 0) { 69 | // Special value for signal fully off. 70 | PCA9685_setPWM(i2c, num, 0, 4096); 71 | } else { 72 | PCA9685_setPWM(i2c, num, 0, val); 73 | } 74 | } 75 | } 76 | 77 | void PCA9685_setPWM(PCA9685_I2C *i2c, uint8_t num, uint16_t on, uint16_t off) { 78 | uint8_t pData[5] = { PCA9685_LED0_ON_L + 4 * num, on, on >> 8, off, off >> 8 }; 79 | if(HAL_I2C_Master_Transmit(i2c->hi2c, i2c->address, pData, 5, 10) != HAL_OK) 80 | return; // For debugging tool in STM 81 | } 82 | 83 | uint8_t PCA9685_getPWM(PCA9685_I2C *i2c, uint8_t num) { 84 | uint8_t Size = PCA9685_LED0_ON_L + 4 * num; 85 | uint8_t pData[Size]; 86 | if(HAL_I2C_Master_Receive(i2c->hi2c, i2c->address, pData, Size, 10) != HAL_OK) 87 | return 0; 88 | return pData[0]; 89 | } 90 | 91 | uint8_t PCA9685_readPrescale(PCA9685_I2C *i2c) { 92 | return read8(i2c, PCA9685_PRESCALE); 93 | } 94 | 95 | void PCA9685_setOutputMode(PCA9685_I2C *i2c, bool totempole) { 96 | uint8_t oldmode = read8(i2c, PCA9685_MODE2); 97 | uint8_t newmode; 98 | if (totempole) { 99 | newmode = oldmode | MODE2_OUTDRV; 100 | } else { 101 | newmode = oldmode & ~MODE2_OUTDRV; 102 | } 103 | write8(i2c, PCA9685_MODE2, newmode); 104 | } 105 | 106 | void PCA9685_setPWMFreq(PCA9685_I2C *i2c, float freq) { 107 | 108 | // Range output modulation frequency is dependant on oscillator 109 | if (freq < 1) 110 | freq = 1; 111 | if (freq > 3500) 112 | freq = 3500; // Datasheet limit is 3052=50MHz/(4*4096) 113 | 114 | float prescaleval = ((i2c->oscillator_freq / (freq * 4096.0)) + 0.5) - 1; 115 | if (prescaleval < PCA9685_PRESCALE_MIN) 116 | prescaleval = PCA9685_PRESCALE_MIN; 117 | if (prescaleval > PCA9685_PRESCALE_MAX) 118 | prescaleval = PCA9685_PRESCALE_MAX; 119 | uint8_t prescale = (uint8_t) prescaleval; 120 | 121 | uint8_t oldmode = read8(i2c, PCA9685_MODE1); 122 | uint8_t newmode = (oldmode & ~MODE1_RESTART) | MODE1_SLEEP; // sleep 123 | write8(i2c, PCA9685_MODE1, newmode); // go to sleep 124 | write8(i2c, PCA9685_PRESCALE, prescale); // set the prescaler 125 | write8(i2c, PCA9685_MODE1, oldmode); 126 | HAL_Delay(5); 127 | 128 | // This sets the MODE1 register to turn on auto increment. 129 | write8(i2c, PCA9685_MODE1, oldmode | MODE1_RESTART | MODE1_AI); 130 | 131 | } 132 | 133 | void PCA9685_setExtClk(PCA9685_I2C *i2c, uint8_t prescale) { 134 | uint8_t oldmode = read8(i2c, PCA9685_MODE1); 135 | uint8_t newmode = (oldmode & ~MODE1_RESTART) | MODE1_SLEEP; // sleep 136 | write8(i2c, PCA9685_MODE1, newmode); // go to sleep, turn off internal oscillator 137 | 138 | // This sets both the SLEEP and EXTCLK bits of the MODE1 register to switch to 139 | // use the external clock. 140 | write8(i2c, PCA9685_MODE1, (newmode |= MODE1_EXTCLK)); 141 | write8(i2c, PCA9685_PRESCALE, prescale); // set the prescaler 142 | HAL_Delay(5); 143 | 144 | // clear the SLEEP bit to start 145 | write8(i2c, PCA9685_MODE1, (newmode & ~MODE1_SLEEP) | MODE1_RESTART | MODE1_AI); 146 | } 147 | 148 | void PCA9685_wakeup(PCA9685_I2C *i2c) { 149 | uint8_t sleep = read8(i2c, PCA9685_MODE1); 150 | uint8_t wakeup = sleep & ~MODE1_SLEEP; // set sleep bit low 151 | write8(i2c, PCA9685_MODE1, wakeup); 152 | } 153 | 154 | void PCA9685_sleep(PCA9685_I2C *i2c) { 155 | uint8_t awake = read8(i2c, PCA9685_MODE1); 156 | uint8_t sleep = awake | MODE1_SLEEP; // set sleep bit high 157 | write8(i2c, PCA9685_MODE1, sleep); 158 | HAL_Delay(5); // wait until cycle ends for sleep to be active 159 | } 160 | 161 | void PCA9685_reset(PCA9685_I2C *i2c) { 162 | write8(i2c, PCA9685_MODE1, MODE1_RESTART); 163 | HAL_Delay(10); 164 | } 165 | 166 | void PCA9685_begin(PCA9685_I2C *i2c, I2C_HandleTypeDef *hi2c, uint8_t address, uint8_t prescale) { 167 | i2c->hi2c = hi2c; 168 | i2c->address = address; 169 | PCA9685_reset(i2c); 170 | if (prescale) { 171 | PCA9685_setExtClk(i2c, prescale); 172 | } else { 173 | // set a default frequency 174 | PCA9685_setPWMFreq(i2c, 1000); 175 | } 176 | // set the default internal frequency 177 | PCA9685_setOscillatorFrequency(i2c, FREQUENCY_OSCILLATOR); 178 | } 179 | -------------------------------------------------------------------------------- /Optimized ILI9341 Touch LCD/Touch Screen/Frames/SAE J1939 Frames/SAE_J1939_DM1_DM2_frame.c: -------------------------------------------------------------------------------- 1 | /* 2 | * SAE_J1939_DM1_DM2_frame.c 3 | * 4 | * Created on: Jul 23, 2021 5 | * Author: Daniel Mårtensson 6 | */ 7 | 8 | #include "../../Touch_screen.h" 9 | #include "../../Hardware/ILI9341.h" 10 | 11 | static void show_DM_frame(char title[], struct DM1 *dm, bool display_from_ecu_address); 12 | static void call_exit(uint8_t *frame_id); 13 | 14 | void STM32_PLC_LCD_Show_SAE_J1939_This_ECU_DM1_Frame(J1939 *j1939, uint8_t *frame_id) { 15 | show_DM_frame("This ECU DM1 codes", &j1939->this_dm.dm1, false); 16 | call_exit(frame_id); 17 | } 18 | 19 | void STM32_PLC_LCD_Show_SAE_J1939_Other_ECU_DM1_Frame(J1939 *j1939, uint8_t *frame_id){ 20 | show_DM_frame("Other ECU DM1 codes", &j1939->from_other_ecu_dm.dm1, true); 21 | call_exit(frame_id); 22 | } 23 | 24 | void STM32_PLC_LCD_Show_SAE_J1939_This_ECU_DM2_Frame(J1939 *j1939, uint8_t *frame_id) { 25 | show_DM_frame("This ECU DM2 codes", &j1939->this_dm.dm2, false); 26 | call_exit(frame_id); 27 | } 28 | 29 | void STM32_PLC_LCD_Show_SAE_J1939_Other_ECU_DM2_Frame(J1939 *j1939, uint8_t *frame_id) { 30 | show_DM_frame("Other ECU DM2 codes", &j1939->from_other_ecu_dm.dm2, true); 31 | call_exit(frame_id); 32 | } 33 | 34 | /* This can be DM1 or DM2 frame */ 35 | static void show_DM_frame(char title[], struct DM1 *dm, bool display_from_ecu_address) { 36 | /* Clear the screen , but not the icons */ 37 | ILI9341_fill_rect(51, 6, 314, 234, COLOR_NAVY); 38 | 39 | /* Write the title */ 40 | ILI9341_draw_horizontal_line(50, 30, 265, COLOR_GREEN); 41 | ILI9341_print_text(title, 55, 10, COLOR_YELLOW, COLOR_NAVY, 1); 42 | 43 | /* SAE Lamp status malfunction indicator */ 44 | char text[50]; 45 | sprintf(text, "Lamp malfunction:%i", dm->SAE_lamp_status_malfunction_indicator); 46 | ILI9341_print_text(text, 55, 35, COLOR_YELLOW, COLOR_NAVY, 1); 47 | 48 | /* SAE Lamp status red stop */ 49 | sprintf(text, "Lamp red stop:%i", dm->SAE_lamp_status_red_stop); 50 | ILI9341_print_text(text, 55, 45, COLOR_YELLOW, COLOR_NAVY, 1); 51 | 52 | /* SAE Lamp status amber warning */ 53 | sprintf(text, "Lamp amber warning:%i", dm->SAE_lamp_status_amber_warning); 54 | ILI9341_print_text(text, 55, 55, COLOR_YELLOW, COLOR_NAVY, 1); 55 | 56 | /* SAE Lamp status protection lamp */ 57 | sprintf(text, "Lamp protection:%i", dm->SAE_lamp_status_protect_lamp); 58 | ILI9341_print_text(text, 55, 65, COLOR_YELLOW, COLOR_NAVY, 1); 59 | 60 | /* SAE Flash lamp malfunction indicator */ 61 | sprintf(text, "Flash malfunction:%i", dm->SAE_flash_lamp_malfunction_indicator); 62 | ILI9341_print_text(text, 55, 75, COLOR_YELLOW, COLOR_NAVY, 1); 63 | 64 | /* SAE Flash lamp red stop */ 65 | sprintf(text, "Flash red stop:%i", dm->SAE_flash_lamp_red_stop); 66 | ILI9341_print_text(text, 55, 85, COLOR_YELLOW, COLOR_NAVY, 1); 67 | 68 | /* SAE Flash lamp amber warning */ 69 | sprintf(text, "Flash amber warning:%i", dm->SAE_flash_lamp_amber_warning); 70 | ILI9341_print_text(text, 55, 95, COLOR_YELLOW, COLOR_NAVY, 1); 71 | 72 | /* SAE Flash lamp protection lamp */ 73 | sprintf(text, "Lamp protection:%i", dm->SAE_flash_lamp_protect_lamp); 74 | ILI9341_print_text(text, 55, 105, COLOR_YELLOW, COLOR_NAVY, 1); 75 | 76 | /* SPN */ 77 | sprintf(text, "SPN:%lu", dm->SPN); 78 | ILI9341_print_text(text, 55, 115, COLOR_YELLOW, COLOR_NAVY, 1); 79 | 80 | /* FMI */ 81 | uint8_t FMI = dm->FMI; 82 | switch (FMI) { 83 | case 0x0: 84 | sprintf(text, "FMI:Above normal most serve"); 85 | break; 86 | case 0x1: 87 | sprintf(text, "FMI:Below normal most serve"); 88 | break; 89 | case 0x2: 90 | sprintf(text, "FMI:Data erratic"); 91 | break; 92 | case 0x3: 93 | sprintf(text, "FMI:Voltage above normal"); 94 | break; 95 | case 0x4: 96 | sprintf(text, "FMI:Voltage below normal"); 97 | break; 98 | case 0x5: 99 | sprintf(text, "FMI:Current below normal"); 100 | break; 101 | case 0x6: 102 | sprintf(text, "FMI:Current above normal"); 103 | break; 104 | case 0x7: 105 | sprintf(text, "FMI:Mechanical system not responding"); 106 | break; 107 | case 0x8: 108 | sprintf(text, "FMI:Abnormal frequency"); 109 | break; 110 | case 0x9: 111 | sprintf(text, "FMI:Abnormal update rate"); 112 | break; 113 | case 0xA: 114 | sprintf(text, "FMI:Abnormal rate change"); 115 | break; 116 | case 0xB: 117 | sprintf(text, "FMI:Root cause not known"); 118 | break; 119 | case 0xC: 120 | sprintf(text, "FMI:Bad intelligent device"); 121 | break; 122 | case 0xD: 123 | sprintf(text, "FMI:Out of calibration"); 124 | break; 125 | case 0xE: 126 | sprintf(text, "FMI:Special instructions"); 127 | break; 128 | case 0xF: 129 | sprintf(text, "FMI:Abnormal least serve"); 130 | break; 131 | case 0x10: 132 | sprintf(text, "FMI:Above normal moderately serve"); 133 | break; 134 | case 0x11: 135 | sprintf(text, "FMI:Below normal least serve"); 136 | break; 137 | case 0x12: 138 | sprintf(text, "FMI:Below normal moderately serve"); 139 | break; 140 | case 0x13: 141 | sprintf(text, "FMI:Received network data in error"); 142 | break; 143 | case 0x14: 144 | sprintf(text, "FMI:Data drifted high"); 145 | break; 146 | case 0x15: 147 | sprintf(text, "FMI:Data drifted low"); 148 | break; 149 | default: 150 | sprintf(text, "FMI:Not available"); 151 | break; 152 | } 153 | ILI9341_print_text(text, 55, 125, COLOR_YELLOW, COLOR_NAVY, 1); 154 | 155 | /* SPN conversion method */ 156 | sprintf(text, "SPN conversion method:%i", dm->SPN_conversion_method); 157 | ILI9341_print_text(text, 55, 135, COLOR_YELLOW, COLOR_NAVY, 1); 158 | 159 | /* Occurrence count */ 160 | sprintf(text, "Occurrence count:%i", dm->occurrence_count); 161 | ILI9341_print_text(text, 55, 145, COLOR_YELLOW, COLOR_NAVY, 1); 162 | 163 | /* From ECU address */ 164 | if(display_from_ecu_address){ 165 | sprintf(text, "From ECU address:%i", dm->from_ecu_address); 166 | ILI9341_print_text(text, 55, 155, COLOR_YELLOW, COLOR_NAVY, 1); 167 | } 168 | } 169 | 170 | static void call_exit(uint8_t *frame_id){ 171 | /* Exit button */ 172 | ILI9341_fill_rect(85, 205, 273, 230, COLOR_GREEN); 173 | ILI9341_hollow_rect(85, 205, 273, 230, COLOR_BLACK); 174 | ILI9341_print_text("Exit frame now", 95, 210, COLOR_BLACK, COLOR_GREEN, 2); 175 | 176 | /* Logic for that button */ 177 | STM32_PLC_LCD_Call_One_Button_Logic(85, 205, 273, 230); 178 | 179 | /* Go back */ 180 | STM32_PLC_LCD_Show_Main_Frame(frame_id, false); 181 | } 182 | -------------------------------------------------------------------------------- /Optimized ILI9341 Touch LCD/Touch Screen/Frames/Analog_input_settings_frame.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Analog_input_settings_frame.c 3 | * 4 | * Created on: 25 juli 2021 5 | * Author: Daniel Mårtensson 6 | */ 7 | 8 | #include "../Touch_screen.h" 9 | #include "../Hardware/ILI9341.h" 10 | #include "../../Functions.h" 11 | 12 | void STM32_PLC_LCD_Show_Analog_Calibration_Frame(uint8_t *frame_id) { 13 | /* Clear the screen , but not the icons */ 14 | ILI9341_fill_rect(51, 6, 314, 234, COLOR_NAVY); 15 | 16 | /* Write the title */ 17 | ILI9341_draw_horizontal_line(50, 30, 265, COLOR_GREEN); 18 | ILI9341_print_text("Set analog calibration for input 0 to 16", 55, 10, COLOR_YELLOW, COLOR_NAVY, 1); 19 | ILI9341_print_text("Values order:Min Max Bias", 55, 20, COLOR_YELLOW, COLOR_NAVY, 1); 20 | 21 | /* Read */ 22 | if(STM32_PLC_SD_Mont_Card() != FR_OK){ 23 | STM32_PLC_LCD_Show_Information_OK_Dialog("Could not mount SD card"); 24 | STM32_PLC_LCD_Show_Main_Frame(frame_id, false); 25 | return; 26 | } 27 | STM32_PLC_SD_Open_Existing_File_With_Read("ANALOG.TXT"); 28 | char text[500]; 29 | STM32_PLC_SD_Read_File(text, sizeof(text)); 30 | STM32_PLC_SD_Close_File(); 31 | STM32_PLC_SD_Unmount_Card(); 32 | 33 | /* Collect analog values */ 34 | char delimiters[4]; 35 | sprintf(delimiters, "%s,", DELIMITER); /* Multiple delimiter */ 36 | float min_max_bias[3*17]; /* 3 values per each analog input channel and we have 17 input channels */ 37 | char line_text[50]; /* We cannot use text array here - It will give hardfault */ 38 | uint16_t y = 25; 39 | for(uint8_t i = 0; i < 17; i++) { 40 | if(i == 0){ 41 | min_max_bias[0 + 3*i] = atoff(strtok(text, delimiters)); 42 | min_max_bias[1 + 3*i] = atoff(strtok(NULL, delimiters)); 43 | min_max_bias[2 + 3*i] = atoff(strtok(NULL, delimiters)); 44 | } else { 45 | min_max_bias[0 + 3*i] = atoff(strtok(NULL, delimiters)); 46 | min_max_bias[1 + 3*i] = atoff(strtok(NULL, delimiters)); 47 | min_max_bias[2 + 3*i] = atoff(strtok(NULL, delimiters)); 48 | } 49 | if(i <= 11){ 50 | sprintf(line_text, "%i=ADC%i:%0.2f %0.2f %0.2f", i, i, min_max_bias[0 + i*3], min_max_bias[1 + i*3], min_max_bias[2 + i*3]); 51 | ILI9341_print_text(line_text, 55, y += 10, COLOR_YELLOW, COLOR_NAVY, 1); 52 | }else{ 53 | sprintf(line_text, "%i=DADC%i:%0.2f %0.2f %0.2f", i, i-12, min_max_bias[0 + i*3], min_max_bias[1 + i*3], min_max_bias[2 + i*3]); 54 | ILI9341_print_text(line_text, 55, y += 10, COLOR_YELLOW, COLOR_NAVY, 1); 55 | } 56 | } 57 | 58 | /* Select settings button */ 59 | ILI9341_fill_rect(85, 205, 273, 230, COLOR_GREEN); 60 | ILI9341_hollow_rect(85, 205, 273, 230, COLOR_BLACK); 61 | ILI9341_print_text("Select setting", 95, 210, COLOR_BLACK, COLOR_GREEN, 2); 62 | 63 | /* Logic for request button */ 64 | STM32_PLC_LCD_Call_One_Button_Logic(85, 205, 273, 230); 65 | 66 | /* Ask the user if */ 67 | if(STM32_PLC_LCD_Show_Question_Yes_No_Dialog("Do you want to change settings?") == 0) { 68 | STM32_PLC_LCD_Show_Main_Frame(frame_id, false); 69 | return; 70 | } 71 | 72 | /* You entered choice 1 - Show numpad */ 73 | bool minusbutton_show = false; 74 | bool decimalbutton_show = false; 75 | float number_value = 0; 76 | if(STM32_PLC_LCD_Show_Numpad_Frame(decimalbutton_show, minusbutton_show, &number_value, "Enter input number between 0 and 16") == 0) { 77 | STM32_PLC_LCD_Show_Main_Frame(frame_id, false); 78 | return; 79 | } 80 | 81 | /* Check */ 82 | uint8_t analog_input_index; 83 | if(number_value < 0) 84 | analog_input_index = 0; 85 | else if(number_value > 16) 86 | analog_input_index = 16; 87 | else 88 | analog_input_index = (uint8_t) number_value; 89 | 90 | /* We need to have decimal and minus button active */ 91 | decimalbutton_show = true; 92 | minusbutton_show = true; 93 | 94 | /* Ask for min value */ 95 | number_value = 0; 96 | if(analog_input_index <= 11) 97 | sprintf(text, "Enter min value for ADC%i", analog_input_index); 98 | else 99 | sprintf(text, "Enter min value for DADC%i", analog_input_index-12); 100 | if(STM32_PLC_LCD_Show_Numpad_Frame(decimalbutton_show, minusbutton_show, &number_value, text) == 0) { 101 | STM32_PLC_LCD_Show_Main_Frame(frame_id, false); 102 | return; 103 | } 104 | float min_value = number_value; 105 | 106 | /* Ask for max value */ 107 | number_value = 0; 108 | if(analog_input_index <= 11) 109 | sprintf(text, "Enter max value for ADC%i", analog_input_index); 110 | else 111 | sprintf(text, "Enter max value for DADC%i", analog_input_index-12); 112 | if(STM32_PLC_LCD_Show_Numpad_Frame(decimalbutton_show, minusbutton_show, &number_value, text) == 0) { 113 | STM32_PLC_LCD_Show_Main_Frame(frame_id, false); 114 | return; 115 | } 116 | float max_value = number_value; 117 | 118 | /* Ask for bias value */ 119 | number_value = 0; 120 | if(analog_input_index <= 11) 121 | sprintf(text, "Enter bias value for ADC%i", analog_input_index); 122 | else 123 | sprintf(text, "Enter bias value for DADC%i", analog_input_index-12); 124 | if(STM32_PLC_LCD_Show_Numpad_Frame(decimalbutton_show, minusbutton_show, &number_value, text) == 0) { 125 | STM32_PLC_LCD_Show_Main_Frame(frame_id, false); 126 | return; 127 | } 128 | float bias_value = number_value; 129 | 130 | /* Apply them */ 131 | if(analog_input_index <= 11) 132 | STM32_PLC_Analog_Input_ADC_Set_Calibration(analog_input_index, min_value, max_value, bias_value); 133 | else if (analog_input_index >= 12 && analog_input_index <= 16) 134 | STM32_PLC_Analog_Input_DADC_Set_Calibration(analog_input_index - 12, min_value, max_value, bias_value); 135 | 136 | /* Overwrite */ 137 | for(uint8_t i = 0; i < 17; i++) { 138 | if(analog_input_index == i){ 139 | min_max_bias[0 + i*3] = min_value; 140 | min_max_bias[1 + i*3] = max_value; 141 | min_max_bias[2 + i*3] = bias_value; 142 | } 143 | } 144 | 145 | /* Write */ 146 | if(STM32_PLC_SD_Mont_Card() != FR_OK){ 147 | STM32_PLC_LCD_Show_Information_OK_Dialog("Could not mount SD card"); 148 | STM32_PLC_LCD_Show_Main_Frame(frame_id, false); 149 | return; 150 | } 151 | STM32_PLC_SD_Open_Existing_File_With_Write("ANALOG.TXT"); 152 | for(uint8_t i = 0; i < 17; i++) { 153 | if(i <= 15) 154 | sprintf(text, "%0.2f,%0.2f,%0.2f%s", min_max_bias[0 + 3*i], min_max_bias[1 + 3*i], min_max_bias[2 + 3*i], DELIMITER); 155 | else 156 | sprintf(text, "%0.2f,%0.2f,%0.2f", min_max_bias[0 + 3*i], min_max_bias[1 + 3*i], min_max_bias[2 + 3*i]); 157 | STM32_PLC_SD_Write_File(text); 158 | } 159 | 160 | /* Exit */ 161 | STM32_PLC_SD_Close_File(); 162 | STM32_PLC_SD_Unmount_Card(); 163 | STM32_PLC_LCD_Show_Main_Frame(frame_id, false); 164 | 165 | } 166 | -------------------------------------------------------------------------------- /Micro SD SPI/ReadMe.md: -------------------------------------------------------------------------------- 1 | # Micro SD SPI 2 | With this code, you can read, write, delete, change text files on a micro SD card. I will show you an example how to get started. 3 | 4 | # How to use 5 | - 1. Begin to implement fatfs_sd.c and fatfs_sd.h where you can access fatfs_sd.h 6 | - 2. Enable UART and SPI and FATFS. Notice that you cannot have so fast SPI here! Maximum 2.25 Mb/s for SD cards. 7 | - 3. Copy over user_diskio.c from this GitHub repository to the user_diskio.c inside your STM32 IDE. 8 | - 4. Copy over the program example to your main.c file 9 | 10 | You can follow the pictures. 11 | UART config: 12 | 13 | ![a](https://raw.githubusercontent.com/DanielMartensson/STM32-Libraries/master/Micro%20SD%20SPI/UART.png) 14 | 15 | SPI config: 16 | 17 | ![a](https://github.com/DanielMartensson/STM32-Libraries/blob/master/Micro%20SD%20SPI/SPI.png) 18 | 19 | FATFS config: 20 | 21 | ![a](https://github.com/DanielMartensson/STM32-Libraries/blob/master/Micro%20SD%20SPI/FATFS.png) 22 | 23 | User_diskio.c and fatfs_sd.h and fatfs.c location: 24 | 25 | ![a](https://github.com/DanielMartensson/STM32-Libraries/blob/master/Micro%20SD%20SPI/User_diskio.png) 26 | 27 | Program example: 28 | ``` 29 | // Include 30 | #include "main.h" 31 | #include "fatfs.h" 32 | #include "Micro SD SPI/fatfs_sd.h" 33 | #include "string.h" 34 | #include "stdio.h" 35 | 36 | // Structures 37 | SPI_HandleTypeDef hspi2; 38 | UART_HandleTypeDef huart2; 39 | 40 | // Variables 41 | FATFS fs; // file system 42 | FIL fil; // File 43 | FILINFO fno; 44 | FRESULT fresult; // result 45 | UINT br, bw; // File read/write count 46 | 47 | /**** capacity related *****/ 48 | FATFS *pfs; 49 | DWORD fre_clust; 50 | uint32_t total, free_space; 51 | 52 | #define BUFFER_SIZE 128 53 | char buffer[BUFFER_SIZE]; // to store strings.. 54 | 55 | int i = 0; 56 | 57 | int bufsize(char *buf) { 58 | int i = 0; 59 | while (*buf++ != '\0') 60 | i++; 61 | return i; 62 | } 63 | 64 | void clear_buffer(void) { 65 | for (int i = 0; i < BUFFER_SIZE; i++) 66 | buffer[i] = '\0'; 67 | } 68 | 69 | void send_uart(char *string) { 70 | uint8_t len = strlen(string); 71 | HAL_UART_Transmit(&huart2, (uint8_t*) string, len, HAL_MAX_DELAY); // transmit in blocking mode 72 | } 73 | 74 | int main() { 75 | 76 | SD_init_handler(&hspi2, SD_CS_GPIO_Port, SD_CS_Pin); 77 | fresult = f_mount(&fs, "/", 1); 78 | if (fresult != FR_OK) 79 | send_uart("ERROR!!! in mounting SD CARD...\n\n"); 80 | else 81 | send_uart("SD CARD mounted successfully...\n\n"); 82 | 83 | /*************** Card capacity details ********************/ 84 | 85 | /* Check free space */ 86 | f_getfree("", &fre_clust, &pfs); 87 | 88 | total = (uint32_t) ((pfs->n_fatent - 2) * pfs->csize * 0.5); 89 | sprintf(buffer, "SD CARD Total Size: \t%lu\n", total); 90 | send_uart(buffer); 91 | clear_buffer(); 92 | free_space = (uint32_t) (fre_clust * pfs->csize * 0.5); 93 | sprintf(buffer, "SD CARD Free Space: \t%lu\n\n", free_space); 94 | send_uart(buffer); 95 | clear_buffer(); 96 | 97 | /************* The following operation is using PUTS and GETS *********************/ 98 | 99 | /* Open file to write/ create a file if it doesn't exist */ 100 | fresult = f_open(&fil, "file1.txt", FA_OPEN_ALWAYS | FA_READ | FA_WRITE); 101 | 102 | /* Writing text */ 103 | f_puts("This data is from the FILE1.txt. And it was written using ...f_puts... ", &fil); 104 | 105 | /* Close file */ 106 | fresult = f_close(&fil); 107 | 108 | if (fresult == FR_OK) 109 | send_uart("File1.txt created and the data is written \n"); 110 | 111 | /* Open file to read */ 112 | fresult = f_open(&fil, "file1.txt", FA_READ); 113 | 114 | /* Read string from the file */ 115 | f_gets(buffer, f_size(&fil), &fil); 116 | 117 | send_uart("File1.txt is opened and it contains the data as shown below\n"); 118 | send_uart(buffer); 119 | send_uart("\n\n"); 120 | 121 | /* Close file */ 122 | f_close(&fil); 123 | 124 | clear_buffer(); 125 | 126 | /**************** The following operation is using f_write and f_read **************************/ 127 | 128 | /* Create second file with read write access and open it */ 129 | fresult = f_open(&fil, "file2.txt", FA_CREATE_ALWAYS | FA_WRITE); 130 | 131 | /* Writing text */ 132 | strcpy(buffer, "This is File2.txt, written using ...f_write... and it says Hello from Controllerstech\n"); 133 | fresult = f_write(&fil, buffer, bufsize(buffer), &bw); 134 | send_uart("File2.txt created and data is written\n"); 135 | 136 | /* Close file */ 137 | f_close(&fil); 138 | 139 | // clearing buffer to show that result obtained is from the file 140 | clear_buffer(); 141 | 142 | /* Open second file to read */ 143 | fresult = f_open(&fil, "file2.txt", FA_READ); 144 | if (fresult == FR_OK) 145 | send_uart("file2.txt is open and the data is shown below\n"); 146 | 147 | /* Read data from the file 148 | * Please see the function details for the arguments */ 149 | f_read(&fil, buffer, f_size(&fil), &br); 150 | send_uart(buffer); 151 | send_uart("\n\n"); 152 | 153 | /* Close file */ 154 | f_close(&fil); 155 | 156 | clear_buffer(); 157 | 158 | /*********************UPDATING an existing file ***************************/ 159 | 160 | /* Open the file with write access */ 161 | fresult = f_open(&fil, "file2.txt", FA_OPEN_EXISTING | FA_READ | FA_WRITE); 162 | 163 | /* Move to offset to the end of the file */ 164 | fresult = f_lseek(&fil, f_size(&fil)); 165 | 166 | if (fresult == FR_OK) 167 | send_uart("About to update the file2.txt\n"); 168 | 169 | /* write the string to the file */ 170 | fresult = f_puts("This is updated data and it should be in the end", &fil); 171 | 172 | f_close(&fil); 173 | 174 | clear_buffer(); 175 | 176 | /* Open to read the file */ 177 | fresult = f_open(&fil, "file2.txt", FA_READ); 178 | 179 | /* Read string from the file */ 180 | fresult = f_read(&fil, buffer, f_size(&fil), &br); 181 | if (fresult == FR_OK) 182 | send_uart("Below is the data from updated file2.txt\n"); 183 | send_uart(buffer); 184 | send_uart("\n\n"); 185 | 186 | /* Close file */ 187 | f_close(&fil); 188 | 189 | clear_buffer(); 190 | 191 | /*************************REMOVING FILES FROM THE DIRECTORY ****************************/ 192 | 193 | fresult = f_unlink("/file1.txt"); 194 | if (fresult == FR_OK) send_uart("file1.txt removed successfully...\n"); 195 | 196 | fresult = f_unlink("/file2.txt"); 197 | if (fresult == FR_OK) send_uart("file2.txt removed successfully...\n"); 198 | 199 | /* Unmount SDCARD */ 200 | fresult = f_mount(NULL, "/", 1); 201 | if (fresult == FR_OK) send_uart ("SD CARD UNMOUNTED successfully...\n"); 202 | 203 | } 204 | ``` 205 | -------------------------------------------------------------------------------- /ILI9341 Touch LCD/LCDCore/TSC2046.c: -------------------------------------------------------------------------------- 1 | /* 2 | * TSC2046.c 3 | * 4 | * Created on: Feb 8, 2020 5 | * Author: Muhammad Yaqoob, rewritted by Daniel Mårtensson 6 | */ 7 | 8 | #include "LCD_ILI9341.h" 9 | 10 | //Functions definitions 11 | // Send TSC2046 Command and wait for a response 12 | static uint16_t TSC2046_SendCommand(ILI9341_SPI *spi, uint8_t cmd) { 13 | uint8_t spiBuf[3] = { 0, 0, 0 }; 14 | uint16_t return16 = 0; 15 | 16 | HAL_GPIO_WritePin(spi->CS_PORT_TOUCH, spi->CS_PIN_TOUCH, GPIO_PIN_RESET); 17 | spiBuf[0] = cmd; 18 | HAL_SPI_Transmit(spi->lcdHandle, spiBuf, 1, 10); 19 | //Wait for response (3 ms) 20 | //HAL_Delay(3); 21 | if (HAL_SPI_Receive(spi->lcdHandle, &spiBuf[1], 2, 10) == HAL_OK){ 22 | return16 = (spiBuf[1] << 4) + (spiBuf[2] >> 4); 23 | }else{ 24 | return16 = 0; 25 | } 26 | HAL_GPIO_WritePin(spi->CS_PORT_TOUCH, spi->CS_PIN_TOUCH, GPIO_PIN_SET); 27 | 28 | return return16; 29 | } 30 | 31 | // Get raw touch data 32 | //i. get x-axis raw touch 12-bit value 33 | static uint16_t TSC2046_getRaw_X(ILI9341_SPI *spi) { 34 | return TSC2046_SendCommand(spi, CMD_X_AXIS | spi->CMD_Default); 35 | } 36 | //ii. get y-axis raw touch 12-bit value 37 | static uint16_t TSC2046_getRaw_Y(ILI9341_SPI *spi) { 38 | return TSC2046_SendCommand(spi, CMD_Y_AXIS | spi->CMD_Default); 39 | } 40 | //iii. get z-axis raw touch 12-bit value 41 | static uint16_t TSC2046_getRaw_Z(ILI9341_SPI *spi) { 42 | return TSC2046_SendCommand(spi, CMD_Z_AXIS | spi->CMD_Default); 43 | } 44 | 45 | // Print calibration points 46 | //i. Top-Left corner point 47 | static void TSC2046_TL_point(ILI9341_SPI *spi) { 48 | ILI9341_fillCircle(spi, 1, 1, 3, COLOR_RED); 49 | ILI9341_printText(spi, "Press here", 20, 30, COLOR_RED, COLOR_RED, 1); 50 | } 51 | //ii. Bottom-Right corner point 52 | static void TSC2046_BR_point(ILI9341_SPI *spi) { 53 | ILI9341_fillCircle(spi, spi->myTS_Calibrate.Width - 1, spi->myTS_Calibrate.Height - 1, 3, COLOR_RED); 54 | ILI9341_printText(spi, "Press here", spi->myTS_Calibrate.Width - 80, spi->myTS_Calibrate.Height - 40, COLOR_RED, COLOR_RED, 1); 55 | } 56 | 57 | // Get orientation (from LCD driver) 58 | static uint8_t TSC2046_getOrientation(ILI9341_SPI *spi) { 59 | return ILI9341_getRotation(spi); 60 | } 61 | 62 | // Poll for touch status 63 | static void TSC2046_GetRawTouch(ILI9341_SPI *spi) { 64 | 65 | //Assign raw touch based on orientation 66 | switch (spi->ScreenOrientation) { 67 | case 1: 68 | spi->localRawTouch.x_touch = 4095 - TSC2046_getRaw_X(spi); 69 | spi->localRawTouch.y_touch = TSC2046_getRaw_Y(spi); 70 | spi->myTS_Calibrate.Width = 230; 71 | spi->myTS_Calibrate.Height = 320; 72 | break; 73 | 74 | case 2: 75 | spi->localRawTouch.x_touch = 4095 - TSC2046_getRaw_Y(spi); 76 | spi->localRawTouch.y_touch = 4095 - TSC2046_getRaw_X(spi); 77 | spi->myTS_Calibrate.Width = 320; 78 | spi->myTS_Calibrate.Height = 240; 79 | break; 80 | 81 | case 3: 82 | spi->localRawTouch.x_touch = TSC2046_getRaw_X(spi); 83 | spi->localRawTouch.y_touch = 4095 - TSC2046_getRaw_Y(spi); 84 | spi->myTS_Calibrate.Width = 230; 85 | spi->myTS_Calibrate.Height = 320; 86 | break; 87 | 88 | case 4: 89 | spi->localRawTouch.x_touch = TSC2046_getRaw_Y(spi); 90 | spi->localRawTouch.y_touch = TSC2046_getRaw_X(spi); 91 | spi->myTS_Calibrate.Width = 320; 92 | spi->myTS_Calibrate.Height = 240; 93 | break; 94 | } 95 | // These are for the calibration 96 | spi->myRawTouchDef.x_touch = spi->localRawTouch.x_touch; 97 | spi->myRawTouchDef.y_touch = spi->localRawTouch.y_touch; 98 | } 99 | 100 | // Calibrate resistive touch panel 101 | void TSC2046_Calibrate(ILI9341_SPI *spi) { 102 | // Set rotation 103 | ILI9341_setRotation(spi, 2); 104 | 105 | uint16_t watchVar1 = 0; 106 | //Get Top-Left corner calibration coordinate 107 | TSC2046_TL_point(spi); 108 | spi->myTS_Calibrate.TL_X = 0; 109 | spi->myTS_Calibrate.TL_Y = 0; 110 | spi->myTS_Calibrate.BR_X = 0; 111 | spi->myTS_Calibrate.BR_Y = 0; 112 | spi->myRawTouchDef.y_touch = 0; 113 | spi->myRawTouchDef.x_touch = 0; 114 | 115 | while (1) { 116 | watchVar1 = TSC2046_getRaw_Z(spi); 117 | if (watchVar1 > 50) { 118 | for (uint8_t i = 0; i < 10; i++) { 119 | 120 | TSC2046_GetRawTouch(spi); 121 | spi->myTS_Calibrate.TL_X += spi->myRawTouchDef.x_touch; 122 | spi->myTS_Calibrate.TL_Y += spi->myRawTouchDef.y_touch; 123 | } 124 | 125 | break; 126 | } 127 | HAL_Delay(10); 128 | } 129 | HAL_Delay(1000); 130 | //Get Bottom-Right corner calibration coordinate 131 | TSC2046_BR_point(spi); 132 | while (1) { 133 | watchVar1 = TSC2046_getRaw_Z(spi); 134 | if (watchVar1 > 50) { 135 | for (uint8_t i = 0; i < 10; i++) { 136 | TSC2046_GetRawTouch(spi); 137 | spi->myTS_Calibrate.BR_X += spi->myRawTouchDef.x_touch; 138 | spi->myTS_Calibrate.BR_Y += spi->myRawTouchDef.y_touch; 139 | } 140 | break; 141 | } 142 | HAL_Delay(10); 143 | } 144 | 145 | spi->myTS_Calibrate.TL_X *= 0.1; 146 | spi->myTS_Calibrate.TL_Y *= 0.1; 147 | 148 | spi->myTS_Calibrate.BR_X *= 0.1; 149 | spi->myTS_Calibrate.BR_Y *= 0.1; 150 | 151 | //1. Calculate X_Diff, Y_Diff 152 | spi->myTS_Calibrate.Scale_X = (spi->myTS_Calibrate.Width + 0.0f) / (spi->myTS_Calibrate.BR_X - spi->myTS_Calibrate.TL_X + 0.0f); 153 | spi->myTS_Calibrate.Scale_Y = (spi->myTS_Calibrate.Height + 0.0f) / (spi->myTS_Calibrate.BR_Y - spi->myTS_Calibrate.TL_Y + 0.0f); 154 | //2. Calculate Scalling () 155 | spi->myTS_Calibrate.Bias_X = -1 - spi->myTS_Calibrate.Scale_X * spi->myTS_Calibrate.TL_X; // -1 is for bias. Change this so you have 100% accuracy at center of the LCD 156 | spi->myTS_Calibrate.Bias_Y = -1 - spi->myTS_Calibrate.Scale_Y * spi->myTS_Calibrate.TL_Y; // -1 is for bias. Change this so you have 100% accuracy at center of the LCD 157 | 158 | } 159 | 160 | // Get touch sccreen data 161 | void TSC2046_GetTouchData(ILI9341_SPI *spi) { 162 | 163 | uint16_t temp16x = 0, temp16y = 0; 164 | //Is screen pressed 165 | if (TSC2046_getRaw_Z(spi) > 50) { 166 | spi->myTsData.isPressed = 1; // True 167 | //Read touch data 168 | for (uint8_t i = 0; i < 10; i++) { 169 | TSC2046_GetRawTouch(spi); 170 | temp16x += spi->localRawTouch.x_touch; 171 | temp16y += spi->localRawTouch.y_touch; 172 | } 173 | spi->localRawTouch.x_touch = temp16x * 0.1; 174 | spi->localRawTouch.y_touch = temp16y * 0.1; 175 | } else 176 | spi->myTsData.isPressed = 0; // false 177 | 178 | //X_Touch value 179 | spi->myTsData.X = spi->myTS_Calibrate.Scale_X * spi->localRawTouch.x_touch + spi->myTS_Calibrate.Bias_X; 180 | 181 | //Y_Touch value 182 | spi->myTsData.Y = spi->myTS_Calibrate.Scale_Y * spi->localRawTouch.y_touch + spi->myTS_Calibrate.Bias_Y; 183 | } 184 | -------------------------------------------------------------------------------- /Optimized ILI9341 Touch LCD/Touch Screen/LCD.c: -------------------------------------------------------------------------------- 1 | /* 2 | * LCD.c 3 | * 4 | * Created on: May 22, 2020 5 | * Author: Daniel Mårtensson 6 | */ 7 | 8 | #include "Functions.h" 9 | #include "Touch Screen/Hardware/ILI9341.h" 10 | 11 | /* 12 | * Initialize LCD and touch 13 | * SPI settings: 14 | * CPHA = 1 Edge 15 | * Prescaler = 8 (be careful for this. Lower than 8 can cause trouble with the touch) 16 | * First bit = MBS first 17 | * CPOL = Low 18 | */ 19 | void STM32_PLC_Start_LCD(SPI_HandleTypeDef *lcdSpi, SPI_HandleTypeDef *touchSpi, GPIO_TypeDef *LCD_CS_PORT, uint16_t LCD_CS_PIN, GPIO_TypeDef *LCD_DC_PORT, uint16_t LCD_DC_PIN, GPIO_TypeDef *LCD_RESET_PORT, uint16_t LCD_RESET_PIN, GPIO_TypeDef *TOUCH_CS_PORT, uint16_t TOUCH_CS_PIN) { 20 | /* Copy SPI settings */ 21 | lcd.lcdSpi = lcdSpi; 22 | lcd.LCD_CS_PORT = LCD_CS_PORT; 23 | lcd.LCD_CS_PIN = LCD_CS_PIN; 24 | lcd.LCD_DC_PORT = LCD_DC_PORT; 25 | lcd.LCD_DC_PIN = LCD_DC_PIN; 26 | HAL_GPIO_WritePin(lcd.LCD_DC_PORT, lcd.LCD_DC_PIN, GPIO_PIN_SET); 27 | lcd.LCD_RESET_PORT = LCD_RESET_PORT; 28 | lcd.LCD_RESET_PIN = LCD_RESET_PIN; 29 | HAL_GPIO_WritePin(lcd.LCD_RESET_PORT, lcd.LCD_RESET_PIN, GPIO_PIN_SET); /* Turn LCD ON */ 30 | lcd._cp437 = 0; // False 31 | lcd.rotationNum = 1; 32 | 33 | /* Reset */ 34 | ILI9341_send_command(ILI9341_RESET); /* software reset command */ 35 | HAL_Delay(100); 36 | ILI9341_send_command(ILI9341_DISPLAY_OFF); /* display off */ 37 | 38 | /* Power Control */ 39 | ILI9341_send_command(ILI9341_POWER1); /* power control */ 40 | ILI9341_send_data(0x26); /* GVDD = 4.75v */ 41 | ILI9341_send_command(ILI9341_POWER2); /* power control */ 42 | ILI9341_send_data(0x11); /* AVDD = VCIx2, VGH = VCIx7, VGL =-VCIx3 */ 43 | 44 | /* VCOM */ 45 | ILI9341_send_command(ILI9341_VCOM1); /* VCOM control */ 46 | ILI9341_send_data(0x35); /* Set the VCOMH voltage (0x35 = 4.025v) */ 47 | ILI9341_send_data(0x3e); /* Set the VCOML voltage (0x3E = -0.950v) */ 48 | ILI9341_send_command(ILI9341_VCOM2); /* VCOM control */ 49 | ILI9341_send_data(0xbe); 50 | 51 | /* Memory Access Control */ 52 | ILI9341_send_command(ILI9341_MAC); 53 | ILI9341_send_data(0x48); 54 | 55 | /* Pixel Format Set - 16-bit per pixel */ 56 | ILI9341_send_command(ILI9341_PIXEL_FORMAT); 57 | ILI9341_send_data(0x55); 58 | 59 | ILI9341_send_command(ILI9341_FRC); 60 | ILI9341_send_data(0); 61 | ILI9341_send_data(0x1F); 62 | 63 | /* DDRAM */ 64 | ILI9341_send_command(ILI9341_COLUMN_ADDR); /* column set */ 65 | ILI9341_send_data(0x00); /* x0_HIGH---0 */ 66 | ILI9341_send_data(0x00); /* x0_LOW----0 */ 67 | ILI9341_send_data(0x00); /* x1_HIGH---240 */ 68 | ILI9341_send_data(0xEF); /* x1_LOW----240 */ 69 | ILI9341_send_command(ILI9341_PAGE_ADDR); /* page address set */ 70 | ILI9341_send_data(0x00); /* y0_HIGH---0 */ 71 | ILI9341_send_data(0x00); /* y0_LOW----0 */ 72 | ILI9341_send_data(0x01); /* y1_HIGH---320 */ 73 | ILI9341_send_data(0x3F); /* y1_LOW----320 */ 74 | 75 | ILI9341_send_command(ILI9341_TEARING_OFF); /* tearing effect off */ 76 | //LCD_write_cmd(ILI9341_TEARING_ON); /* tearing effect on */ 77 | //LCD_write_cmd(ILI9341_DISPLAY_INVERSION); /* display inversion */ 78 | ILI9341_send_command(ILI9341_Entry_Mode_Set); /* entry mode set */ 79 | /* Deep Standby Mode: OFF 80 | * Set the output level of gate driver G1-G320: Normal display 81 | * Low voltage detection: Disable 82 | */ 83 | ILI9341_send_data(0x07); 84 | 85 | /* Display */ 86 | ILI9341_send_command(ILI9341_DFC); /* display function control */ 87 | /* Set the scan mode in non-display area 88 | * Determine source/VCOM output in a non-display area in the partial display mode 89 | */ 90 | ILI9341_send_data(0x0a); 91 | /* Select whether the liquid crystal type is normally white type or normally black type 92 | * Sets the direction of scan by the gate driver in the range determined by SCN and NL 93 | * Select the shift direction of outputs from the source driver 94 | * Sets the gate driver pin arrangement in combination with the GS bit to select the optimal scan mode for the module 95 | * Specify the scan cycle interval of gate driver in non-display area when PTG to select interval scan 96 | */ 97 | ILI9341_send_data(0x82); 98 | /* Sets the number of lines to drive the LCD at an interval of 8 lines */ 99 | ILI9341_send_data(0x27); 100 | ILI9341_send_data(0x00); /* clock divisor */ 101 | 102 | ILI9341_send_command(ILI9341_SLEEP_OUT); /* sleep out */ 103 | HAL_Delay(100); 104 | ILI9341_send_command(ILI9341_DISPLAY_ON); /* display on */ 105 | HAL_Delay(100); 106 | ILI9341_send_command(ILI9341_GRAM); /* memory write */ 107 | HAL_Delay(5); 108 | 109 | /* Touch Screen SPI */ 110 | TS_TOUCH_RAW_Def myRawTouchDef = {0}; 111 | TS_TOUCH_RAW_Def localRawTouch = {0}; 112 | TS_CALIBRATE_Def myTS_Calibrate = {0}; 113 | lcd.myTS_Calibrate = myTS_Calibrate; 114 | lcd.localRawTouch = localRawTouch; 115 | lcd.myRawTouchDef = myRawTouchDef; 116 | lcd.touchSpi = touchSpi; 117 | lcd.TOUCH_CS_PORT = TOUCH_CS_PORT; 118 | lcd.TOUCH_CS_PIN = TOUCH_CS_PIN; 119 | lcd.CMD_Default = 0x84; 120 | } 121 | 122 | void STM32_PLC_LCD_Calibrate_Touch() { 123 | TSC2046_Calibrate(); 124 | } 125 | 126 | void STM32_PLC_LCD_Get_Touch_Calibration_Parameters(float *Scale_X, float *Scale_Y, float *Bias_X, float *Bias_Y){ 127 | TSC2046_GetTouchCalibrationParameters(Scale_X, Scale_Y, Bias_X, Bias_Y); 128 | } 129 | 130 | void STM32_PLC_LCD_Set_Touch_Calibration_Parameters(float *Scale_X, float *Scale_Y, float *Bias_X, float *Bias_Y){ 131 | TSC2046_SetTouchCalibrationParameters(Scale_X, Scale_Y, Bias_X, Bias_Y); 132 | } 133 | 134 | void STM32_PLC_LCD_Get_Touch_Data() { 135 | TSC2046_GetTouchData(); 136 | } 137 | -------------------------------------------------------------------------------- /DS3231/DS3231/DS3231.c: -------------------------------------------------------------------------------- 1 | /* 2 | * DS3231.c 3 | * 4 | * Created on: 6 mars 2020 5 | * Author: Daniel Mårtensson 6 | */ 7 | 8 | #include "DS3231.h" 9 | 10 | // Private functions 11 | static void setAlarmSecond(DS3231_I2C* i2c, uint8_t seconds, uint8_t address); 12 | static void setAlarmMinutes(DS3231_I2C* i2c, uint8_t minutes, uint8_t address); 13 | static void setAlarmHours(DS3231_I2C* i2c, uint8_t hours, uint8_t address); 14 | static void setAlarmDay(DS3231_I2C* i2c, uint8_t days, uint8_t address); 15 | static void setAlarmDate(DS3231_I2C* i2c, uint8_t dates, uint8_t address); 16 | 17 | 18 | 19 | /* Create the structure 20 | * Address table: 21 | * A2, A1, A0 = 000 = 0x0 22 | * A2, A1, A0 = 001 = 0x1 23 | * A2, A1, A0 = 010 = 0x2 24 | * A2, A1, A0 = 011 = 0x3 25 | * A2, A1, A0 = 100 = 0x4 26 | * A2, A1, A0 = 101 = 0x5 27 | * A2, A1, A0 = 110 = 0x6 28 | * A2, A1, A0 = 111 = 0x7 29 | */ 30 | void DS3231_init(DS3231_I2C* i2c, I2C_HandleTypeDef* hi2c, uint8_t addr, uint8_t enableWeekAlarm, uint8_t enableDateAlarm){ 31 | i2c->addr = 0xD0 | (addr << 1); 32 | i2c->hi2c = hi2c; 33 | 34 | // Check if we have the correct connection with our RTC 35 | if (HAL_I2C_IsDeviceReady(i2c->hi2c, i2c->addr, 10, 10) != HAL_OK){ 36 | HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET); // This MUST have GPIO PA5 ready to use - ERROR I2C - Wrong address 37 | return; 38 | } 39 | 40 | // Set the control. Enable/disable the alarms and enable alarm output SQW 41 | uint8_t pData[2] = {0x0E, 0x1C | (enableWeekAlarm << 1) | enableDateAlarm}; 42 | HAL_I2C_Master_Transmit(i2c->hi2c, i2c->addr, pData, 2, 10); 43 | DS3231_offTriggAlarm(i2c); 44 | } 45 | 46 | /* 47 | * Set the clock. 48 | * Second: 49 | * Variable second can be 0-59. 50 | * 51 | * Minute: 52 | * Variable minutes can be 0-59. 53 | * 54 | * Hour: 55 | * Variable hours can be 0-23. 56 | * 57 | * Day: 58 | * Variable days can be 1-7. 59 | * 60 | * Date: 61 | * Variable dates can be 1-31. 62 | * 63 | * Month: 64 | * Variable months can be 1-12 65 | * 66 | * Year: 67 | * Variable years can be 0-99 68 | */ 69 | void DS3231_setClock(DS3231_I2C* i2c, uint8_t seconds, uint8_t minutes, uint8_t hours, uint8_t days, uint8_t dates, uint8_t months, uint8_t years){ 70 | 71 | uint8_t pData[8]; 72 | pData[0] = 0x00; // Address for the first register 73 | 74 | // Seconds 75 | uint8_t ten = seconds/10; // This will result 0, 1, 2, 3, 4, 5 76 | uint8_t part = seconds - ten*10; // This will result 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 77 | pData[1] = (ten << 4) | part; 78 | 79 | // Minutes 80 | ten = minutes/10; // This will result 0, 1, 2, 3, 4, 5 81 | part = minutes - ten*10; // This will result 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 82 | pData[2] = (ten << 4) | part; 83 | 84 | // Hours 85 | ten = hours/10; // This will result 0, 1, 2. 86 | part = hours - ten*10; // This will result 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 87 | pData[3] = (ten << 4) | part; 88 | 89 | // Day 90 | pData[4] = days; 91 | 92 | // Date 93 | ten = dates/10; // This will result 0, 1, 2, 3. 94 | part = dates - ten*10; // This will result 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 95 | pData[5] = (ten << 4) | part; 96 | 97 | // Month 98 | ten = months/10; 99 | part = months - ten*10; 100 | pData[6] = (ten << 4) | part; 101 | 102 | // Year 103 | ten = years/10; 104 | part = years - ten*10; 105 | pData[7] = (ten << 4) | part; 106 | 107 | HAL_I2C_Master_Transmit(i2c->hi2c, i2c->addr, pData, 8, 10); 108 | 109 | } 110 | 111 | void DS3231_getClock(DS3231_I2C* i2c){ 112 | 113 | uint8_t rData[7]; 114 | HAL_I2C_Mem_Read(i2c->hi2c, i2c->addr, 0x00, 1, rData, 7, 1000); 115 | 116 | // Second 117 | i2c->second = (10*(rData[0] >> 4)) + (rData[0] & 0xF); 118 | i2c->minute = (10*(rData[1] >> 4)) + (rData[1] & 0xF); 119 | i2c->hour = (10*(rData[2] >> 4)) + (rData[2] & 0xF); // 24-hour clock 120 | i2c->day = rData[3]; 121 | i2c->date = (10*(rData[4] >> 4)) + (rData[4] & 0xF); 122 | i2c->month = (10*(rData[5] >> 4)) + (rData[5] & 0xF); 123 | i2c->year = (10*(rData[6] >> 4)) + (rData[6] & 0xF); 124 | 125 | } 126 | 127 | // Exactly the same as DS3231_setClock arguments. 128 | void DS3231_setDateAlarm(DS3231_I2C* i2c, uint8_t seconds, uint8_t minutes, uint8_t hours, uint8_t dates){ 129 | setAlarmSecond(i2c, seconds, 0x07); 130 | setAlarmMinutes(i2c, minutes, 0x08); 131 | setAlarmHours(i2c, hours, 0x09); 132 | setAlarmDate(i2c, dates, 0xA); 133 | } 134 | 135 | // Exactly the same as DS3231_setClock arguments. 136 | void DS3231_setWeekAlarm(DS3231_I2C* i2c, uint8_t minutes, uint8_t hours, uint8_t days){ 137 | setAlarmMinutes(i2c, minutes, 0xB); 138 | setAlarmHours(i2c, hours, 0xC); 139 | setAlarmDay(i2c, days, 0xD); 140 | } 141 | 142 | // Un-Trigger of the alarm 143 | void DS3231_offTriggAlarm(DS3231_I2C* i2c){ 144 | uint8_t pData[2] = {0x0F, 0b00000000}; 145 | HAL_I2C_Master_Transmit(i2c->hi2c, i2c->addr, pData, 2, 10); 146 | } 147 | 148 | // Read the alarm status. 0b11 = Both alarms are on. 0b1 = Only date alarm is on. 0b10 = Only week alarm is on 149 | uint8_t DS3231_readALarmStatus(DS3231_I2C* i2c){ 150 | uint8_t rData = 0xF; 151 | HAL_I2C_Master_Transmit(i2c->hi2c, i2c->addr, &rData, 1, 10); 152 | HAL_I2C_Master_Receive(i2c->hi2c, i2c->addr, &rData, 1, 10); 153 | rData = rData << 6; 154 | rData = rData >> 6; 155 | return rData; // We only want 11, 10, 01 or 00 156 | } 157 | 158 | static void setAlarmSecond(DS3231_I2C* i2c, uint8_t seconds, uint8_t address){ 159 | uint8_t ten = seconds/10; 160 | uint8_t second = seconds - ten*10; 161 | uint8_t pData[2] = {address, (ten << 4) | second}; 162 | HAL_I2C_Master_Transmit(i2c->hi2c, i2c->addr, pData, 2, 10); 163 | } 164 | 165 | static void setAlarmMinutes(DS3231_I2C* i2c, uint8_t minutes, uint8_t address){ 166 | uint8_t ten = minutes/10; 167 | uint8_t minute = minutes - ten*10; 168 | uint8_t pData[2] = {address, (ten << 4) | minute}; 169 | HAL_I2C_Master_Transmit(i2c->hi2c, i2c->addr, pData, 2, 10); 170 | } 171 | 172 | static void setAlarmHours(DS3231_I2C* i2c, uint8_t hours, uint8_t address){ 173 | uint8_t ten = hours/10; 174 | uint8_t hour = hours - ten*10; 175 | uint8_t pData[2]; 176 | pData[0] = address; 177 | pData[1] = (ten << 4) | hour; 178 | HAL_I2C_Master_Transmit(i2c->hi2c, i2c->addr, pData, 2, 10); 179 | 180 | } 181 | 182 | static void setAlarmDay(DS3231_I2C* i2c, uint8_t days, uint8_t address){ 183 | uint8_t ten = days/10; 184 | uint8_t day = days - ten*10; 185 | uint8_t pData[2] = {address, (1 << 6) | (ten << 4) | day}; 186 | HAL_I2C_Master_Transmit(i2c->hi2c, i2c->addr, pData, 2, 10); 187 | } 188 | 189 | static void setAlarmDate(DS3231_I2C* i2c, uint8_t dates, uint8_t address){ 190 | uint8_t ten = dates/10; 191 | uint8_t date = dates - ten*10; 192 | uint8_t pData[2] = {address, (ten << 4) | date}; 193 | HAL_I2C_Master_Transmit(i2c->hi2c, i2c->addr, pData, 2, 10); 194 | } 195 | --------------------------------------------------------------------------------