Merge branch 'display'

- merge display branch with outsourced and reworked display code
- resolve merge conflict caused by new ENCODER_TEST feature in main
This commit is contained in:
jonny_l480 2022-08-26 13:59:15 +02:00
commit 5a3c6b15bc
6 changed files with 344 additions and 87 deletions

View File

@ -236,7 +236,7 @@ esp_err_t max7219_draw_text_7seg(max7219_t *dev, uint8_t pos, const char *s)
{
CHECK_ARG(dev && s);
while (s && pos < dev->digits)
while (*s != '\0' && pos < dev->digits)
{
uint8_t c = get_char(dev, *s);
if (*(s + 1) == '.')

View File

@ -5,6 +5,7 @@ idf_component_register(
"control.cpp"
"buzzer.cpp"
"vfd.cpp"
"display.cpp"
INCLUDE_DIRS
"."
)

View File

@ -1,32 +1,5 @@
#include "control.hpp"
//========================
//===== init display =====
//========================
max7219_t init_display(){
// Configure SPI bus
spi_bus_config_t cfg;
cfg.mosi_io_num = DISPLAY_PIN_NUM_MOSI;
cfg.miso_io_num = -1;
cfg.sclk_io_num = DISPLAY_PIN_NUM_CLK;
cfg.quadwp_io_num = -1;
cfg.quadhd_io_num = -1;
cfg.max_transfer_sz = 0;
cfg.flags = 0;
ESP_ERROR_CHECK(spi_bus_initialize(HOST, &cfg, 1));
// Configure device
max7219_t dev;
dev.cascade_size = 2;
dev.digits = 0;
dev.mirrored = true;
ESP_ERROR_CHECK(max7219_init_desc(&dev, HOST, MAX7219_MAX_CLOCK_SPEED_HZ, DISPLAY_PIN_NUM_CS));
ESP_ERROR_CHECK(max7219_init(&dev));
//0...15
ESP_ERROR_CHECK(max7219_set_brightness(&dev, 12));
return dev;
}
//========================
//===== init encoder =====
@ -81,7 +54,6 @@ static const char *TAG = "control"; //tag for logging
const char* systemStateStr[5] = {"COUNTING", "WINDING_START", "WINDING", "TARGET_REACHED", "MANUAL"};
systemState_t controlState = COUNTING;
max7219_t display; //display device
char buf_disp[20]; //both displays
char buf_disp1[10];// 8 digits + decimal point + \0
char buf_disp2[10];// 8 digits + decimal point + \0
@ -91,7 +63,6 @@ rotary_encoder_info_t encoder; //encoder device/info
QueueHandle_t encoder_queue = NULL; //encoder event queue
rotary_encoder_state_t encoderState;
uint8_t count = 0; //count for testing
uint32_t timestamp_pageSwitched = 0;
bool page = false; //store page number currently displayed
int lengthNow = 0; //length measured in mm
@ -120,19 +91,25 @@ void changeState (systemState_t stateNew) {
//===== handle Stop Condition =====
//function that checks whether start button is released or target is reached (used in multiple states)
//returns true when stopped, false when no action
bool handleStopCondition(){
bool handleStopCondition(handledDisplay * displayTop, handledDisplay * displayBot){
//--- stop conditions ---
//stop conditions that are checked in any mode
//target reached
if (lengthRemaining <= 0 ) {
changeState(TARGET_REACHED);
vfd_setState(false);
displayTop->blink(1, 0, 1500, " S0LL ");
displayBot->blink(1, 0, 1500, "ERREICHT");
buzzer.beep(2, 100, 100);
return true;
}
//start button released
else if (SW_START.state == false) {
changeState(COUNTING);
vfd_setState(false);
displayTop->blink(2, 900, 1000, "- STOP -");
displayBot->blink(2, 900, 1000, " TASTER ");
buzzer.beep(3, 200, 100);
return true;
} else {
return false;
@ -171,28 +148,19 @@ void setDynSpeedLvl(uint8_t lvlMax = 3){
//========================
void task_control(void *pvParameter)
{
//initialize display
display = init_display();
//initialize encoder
encoder_queue = init_encoder(&encoder);
//-----------------------------------
//------- display welcome msg -------
//-----------------------------------
//initialize display
max7219_t two7SegDisplays = display_init();
//create two separate handled display instances
handledDisplay displayTop(two7SegDisplays, 0);
handledDisplay displayBot(two7SegDisplays, 8);
//--- display welcome msg ---
//display welcome message on two 7 segment displays
//show name and date
ESP_LOGI(TAG, "showing startup message...");
max7219_clear(&display);
max7219_draw_text_7seg(&display, 0, "CUTTER 20.08.2022");
// 1234567812 34 5678
vTaskDelay(pdMS_TO_TICKS(700));
//scroll "hello" over 2 displays
for (int offset = 0; offset < 23; offset++) {
max7219_clear(&display);
char hello[23] = " HELL0 ";
max7219_draw_text_7seg(&display, 0, hello + (22 - offset) );
vTaskDelay(pdMS_TO_TICKS(50));
}
//currently show name and date and scrolling 'hello'
display_ShowWelcomeMsg(two7SegDisplays);
//================
@ -278,6 +246,7 @@ void task_control(void *pvParameter)
}
if (SW_SET.fallingEdge) {
buzzer.beep(2, 70, 50);
displayBot.blink(2, 100, 100, "S0LL ");
}
@ -286,14 +255,17 @@ void task_control(void *pvParameter)
if (SW_PRESET1.risingEdge){
lengthTarget = 1000;
buzzer.beep(lengthTarget/1000, 25, 30);
displayBot.blink(3, 100, 100, "S0LL ");
}
else if (SW_PRESET2.risingEdge) {
lengthTarget = 5000;
buzzer.beep(lengthTarget/1000, 25, 30);
displayBot.blink(2, 100, 100, "S0LL ");
}
else if (SW_PRESET3.risingEdge) {
lengthTarget = 10000;
buzzer.beep(lengthTarget/1000, 25, 30);
displayBot.blink(2, 100, 100, "S0LL ");
}
}
@ -309,6 +281,7 @@ void task_control(void *pvParameter)
switch (controlState) {
case COUNTING: //no motor action
vfd_setState(false);
//TODO check stop condition before starting - prevents motor from starting 2 cycles when
//--- start winding to length ---
if (SW_START.risingEdge) {
changeState(WINDING_START);
@ -326,14 +299,14 @@ void task_control(void *pvParameter)
if (esp_log_timestamp() - timestamp_motorStarted > 2000) {
changeState(WINDING);
}
handleStopCondition(); //stops if button released or target reached
handleStopCondition(&displayTop, &displayBot); //stops if button released or target reached
//TODO: cancel when there was no cable movement during start time?
break;
case WINDING: //wind fast, slow down when close
//set vfd speed depending on remaining distance
setDynSpeedLvl(); //slow down when close to target
handleStopCondition(); //stops if button released or target reached
handleStopCondition(&displayTop, &displayBot); //stops if button released or target reached
//TODO: cancel when there is no cable movement anymore e.g. empty / timeout?
break;
@ -343,6 +316,12 @@ void task_control(void *pvParameter)
if ( lengthRemaining > 0 ) {
changeState(COUNTING);
}
//show msg when trying to start, but target is reached
if (SW_START.risingEdge){
buzzer.beep(3, 40, 30);
displayTop.blink(2, 600, 800, " S0LL ");
displayBot.blink(2, 600, 800, "ERREICHT");
}
break;
case MANUAL: //manually control motor via preset buttons + poti
@ -359,48 +338,84 @@ void task_control(void *pvParameter)
else if ( SW_PRESET1.state && !SW_PRESET3.state ) {
vfd_setSpeedLevel(level); //TODO: use poti input for level
vfd_setState(true, REV);
sprintf(buf_disp2, "[--%02i ", level);
// 123 45 678
}
//P2 + P3 -> turn right
else if ( SW_PRESET3.state && !SW_PRESET1.state ) {
vfd_setSpeedLevel(level); //TODO: use poti input for level
vfd_setState(true, FWD);
sprintf(buf_disp2, " %02i--]", level);
}
//no valid switch combination -> turn off motor
else {
vfd_setState(false);
sprintf(buf_disp2, " %02i ", level);
}
}
//---------------------------
//--------- display ---------
//---------------------------
//--------------------------
//------ encoder test ------
//--------------------------
#ifdef ENCODER_TEST
//run display handle functions
displayTop.handle();
displayBot.handle();
//-- show encoder steps on display1 ---
sprintf(buf_disp1, "EN %05d", encoderState.position); //count
displayTop.showString(buf_disp1);
//--- show converted distance on display2 ---
sprintf(buf_disp2, "Met %5.3f", (float)lengthNow/1000); //m
displayBot.showString(buf_disp2);
//--- beep every 1m ---
//note: only works precicely in forward/positive direction
if (lengthNow % 1000 < 50) { //with tolerance in case of missed exact value
if (fabs(lengthNow - lengthBeeped) >= 900) { //dont beep multiple times at same meter
//TODO: add case for reverse direction. currently beeps 0.1 too early
buzzer.beep(1, 400, 100);
buzzer.beep(1, 400, 100 );
lengthBeeped = lengthNow;
}
}
#else
//-- show current position on display1 ---
//sprintf(buf_tmp, "%06.1f cm", (float)lengthNow/10); //cm
sprintf(buf_tmp, "1ST %5.4f", (float)lengthNow/1000); //m
//--------------------------
//-------- display1 --------
//--------------------------
//run handle function
displayTop.handle();
//show current position on display
sprintf(buf_tmp, "1ST %5.4f", (float)lengthNow/1000);
// 123456789
//limit length to 8 digits + decimal point (drop decimal places when it does not fit)
sprintf(buf_disp1, "%.9s", buf_tmp);
displayTop.showString(buf_disp1);
//--------------------------
//-------- display2 --------
//--------------------------
//run handle function
displayBot.handle();
//setting target length: blink target length
if (SW_SET.state == true){
sprintf(buf_tmp, "S0LL%5.3f", (float)lengthTarget/1000);
displayBot.blinkStrings(buf_tmp, "S0LL ", 300, 100);
}
//manual state: blink "manual"
else if (controlState == MANUAL) {
displayBot.blinkStrings(" MANUAL ", buf_disp2, 1000, 1000);
}
//otherwise show target length
else {
//sprintf(buf_disp2, "%06.1f cm", (float)lengthTarget/10); //cm
sprintf(buf_tmp, "S0LL%5.3f", (float)lengthTarget/1000); //m
// 1234 5678
displayBot.showString(buf_tmp);
}
//--- show target length on display2 ---
//sprintf(buf_disp2, "%06.1f cm", (float)lengthTarget/10); //cm
sprintf(buf_disp2, "S0LL%5.3f", (float)lengthTarget/1000); //m
// 123456789
#endif
//TODO: blink disp2 when set button pressed
@ -408,30 +423,6 @@ void task_control(void *pvParameter)
//TODO: write "MAN CTL" to disp2 when in manual mode
//TODO: display or blink "REACHED" when reached state and start pressed
//--- write to display ---
//max7219_clear(&display); //results in flickering display if same value anyways
max7219_draw_text_7seg(&display, 0, buf_disp1);
max7219_draw_text_7seg(&display, 8, buf_disp2);
// //switch between two display pages
// if (esp_log_timestamp() - timestamp_pageSwitched > 1000){
// timestamp_pageSwitched = esp_log_timestamp();
// page = !page;
// }
// max7219_clear(&display);
// if (page){
// //display current position
// display_current_distance(&display, &encoder);
// } else {
// //display counter
// sprintf(display_buf, "lvl: %02d", count);
// max7219_draw_text_7seg(&display, 0, display_buf);
// //count++;
// }
//sprintf(display_buf, "S0LL 12.3");
//max7219_draw_text_7seg(&display, 8, display_buf);
}
}

View File

@ -10,8 +10,9 @@ extern "C"
#include "esp_log.h"
#include "driver/adc.h"
#include <max7219.h>
#include "rotary_encoder.h"
#include "max7219.h"
}
#include <cmath>
@ -19,6 +20,7 @@ extern "C"
#include "gpio_evaluateSwitch.hpp"
#include "buzzer.hpp"
#include "vfd.hpp"
#include "display.hpp"

198
main/display.cpp Normal file
View File

@ -0,0 +1,198 @@
#include "display.hpp"
//=== variables ===
static const char *TAG = "display"; //tag for logging
//==============================
//======== init display ========
//==============================
//initialize display with parameters defined in config.hpp
//TODO: dont use global variables/macros here
max7219_t display_init(){
ESP_LOGI(TAG, "initializing display...");
// Configure SPI bus
spi_bus_config_t cfg;
memset(&cfg, 0, sizeof(spi_bus_config_t)); //init bus config with 0 to prevent bugs with random flags
cfg.mosi_io_num = DISPLAY_PIN_NUM_MOSI;
cfg.miso_io_num = -1;
cfg.sclk_io_num = DISPLAY_PIN_NUM_CLK;
cfg.quadwp_io_num = -1;
cfg.quadhd_io_num = -1;
cfg.max_transfer_sz = 0;
cfg.flags = 0;
ESP_ERROR_CHECK(spi_bus_initialize(HOST, &cfg, 1));
// Configure device
max7219_t dev;
dev.cascade_size = 2;
dev.digits = 0;
dev.mirrored = true;
ESP_ERROR_CHECK(max7219_init_desc(&dev, HOST, MAX7219_MAX_CLOCK_SPEED_HZ, DISPLAY_PIN_NUM_CS));
ESP_ERROR_CHECK(max7219_init(&dev));
//0...15
ESP_ERROR_CHECK(max7219_set_brightness(&dev, 8));
return dev;
//display = dev;
ESP_LOGI(TAG, "initializing display - done");
}
//===================================
//======= display welcome msg =======
//===================================
void display_ShowWelcomeMsg(max7219_t dev){
//display welcome message on two 7 segment displays
//show name and date
ESP_LOGI(TAG, "showing startup message...");
max7219_clear(&dev);
max7219_draw_text_7seg(&dev, 0, "CUTTER 20.08.2022");
// 1234567812 34 5678
vTaskDelay(pdMS_TO_TICKS(700));
//scroll "hello" over 2 displays
for (int offset = 0; offset < 23; offset++) {
max7219_clear(&dev);
char hello[40] = " HELL0 ";
max7219_draw_text_7seg(&dev, 0, hello + (22 - offset) );
vTaskDelay(pdMS_TO_TICKS(50));
}
}
//---------------------------------
//---------- constructor ----------
//---------------------------------
handledDisplay::handledDisplay(max7219_t displayDevice, uint8_t posStart_f) {
ESP_LOGI(TAG, "Creating handledDisplay instance with startPos at %i", posStart);
//copy variables
dev = displayDevice;
posStart = posStart_f;
}
//--------------------------------
//---------- showString ----------
//--------------------------------
//function that displays a given string on the display
void handledDisplay::showString(const char * buf, uint8_t pos_f){
//calculate actual absolute position
posCurrent = posStart + pos_f;
//copy the desired string
strcpy(strOn, buf);
//exit blinking mode
if (mode == displayMode::BLINK_STRINGS){
mode = displayMode::NORMAL;
ESP_LOGI(TAG, "pos:%i - disable blink strings mode -> normal mode str='%s'", posStart, strOn);
}
handle(); //draws the text depending on mode
}
//TODO: blinkStrings() and blink() are very similar - can be optimized?
//only difficulty currently is the reset behaivor of blinkStrings through showString (blink does not reset)
//----------------------------------
//---------- blinkStrings ----------
//----------------------------------
//function switches between two strings in a given interval
void handledDisplay::blinkStrings(const char * strOn_f, const char * strOff_f, uint32_t msOn_f, uint32_t msOff_f){
//copy/update variables
strcpy(strOn, strOn_f);
strcpy(strOff, strOff_f);
msOn = msOn_f;
msOff = msOff_f;
//if changed to blink mode just now:
if (mode != displayMode::BLINK_STRINGS) {
//switch mode
ESP_LOGI(TAG, "pos:%i - toggle blink strings mode on/off=%d/%d stings='%s'/'%s'", posStart, msOn, msOff, strOn, strOff);
mode = displayMode::BLINK_STRINGS;
//start with on state
state = true;
timestampOn = esp_log_timestamp();
}
//run handle function for display update
handle();
}
//-------------------------------
//------------ blink ------------
//-------------------------------
//function triggers certain count and interval of off durations
void handledDisplay::blink(uint8_t count_f, uint32_t msOn_f, uint32_t msOff_f, const char * strOff_f) {
//copy/update parameters
count = count_f;
msOn = msOn_f;
msOff = msOff_f;
strcpy(strOff, strOff_f);
//FIXME this strings length must be dynamic depending on display size (posEnd - posStart) -> otherwise overwrites next segments if other display size or start pos
//if changed to blink mode just now:
if (mode != displayMode::BLINK) {
//set to blink mode
mode = displayMode::BLINK;
ESP_LOGI(TAG, "pos:%i - start blinking: count=%i on/off=%d/%d sting='%s'",posStart, count, msOn, msOff, strOff);
//start with off state
state = false;
timestampOff = esp_log_timestamp();
}
//run handle function for display update
handle();
}
//--------------------------------
//------------ handle ------------
//--------------------------------
//function that handles time based modes
//writes text to the 7 segment display depending on the current mode
void handledDisplay::handle() {
switch (mode){
case displayMode::NORMAL:
//daw given string
max7219_draw_text_7seg(&dev, posCurrent, strOn);
break;
case displayMode::BLINK:
case displayMode::BLINK_STRINGS:
//--- define state on/off ---
if (state == true){ //display in ON state
if (esp_log_timestamp() - timestampOn > msOn){
state = false;
timestampOff = esp_log_timestamp();
//decrement remaining counts in BLINK mode each cycle
if (mode == displayMode::BLINK) count--;
}
} else { //display in OFF state
if (esp_log_timestamp() - timestampOff > msOff) {
state = true;
timestampOn = esp_log_timestamp();
}
}
//--- draw text of current state ---
if (state) {
max7219_draw_text_7seg(&dev, posStart, strOn);
} else {
max7219_draw_text_7seg(&dev, posStart, strOff);
}
//--- check finished condition in BLINK mode ---
if (mode == displayMode::BLINK){
if (count == 0) {
mode = displayMode::NORMAL;
ESP_LOGI(TAG, "pos:%i - finished blinking -> normal mode", posStart);
}
}
break;
}
}

65
main/display.hpp Normal file
View File

@ -0,0 +1,65 @@
#pragma once
extern "C"
{
#include <stdio.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <esp_idf_version.h>
#include "freertos/queue.h"
#include "esp_system.h"
#include "esp_log.h"
#include "driver/adc.h"
#include <max7219.h>
#include "rotary_encoder.h"
}
#include <cstring>
#include "config.hpp"
//function for initializing the display using configuration from macros in config.hpp
max7219_t display_init();
//show welcome message on the entire display
void display_ShowWelcomeMsg(max7219_t displayDevice);
enum class displayMode {NORMAL, BLINK_STRINGS, BLINK};
class handledDisplay {
public:
//--- constructor ---
//TODO add posMax to prevent writing in segments of other instance
handledDisplay(max7219_t displayDevice, uint8_t posStart);
//--- methods ---
void showString(const char * buf, uint8_t pos = 0);
//function switches between two strings in a given interval
void blinkStrings(const char * strOn, const char * strOff, uint32_t msOn, uint32_t msOff);
//triggers certain count of blinking between currently shown string and off or optional certain string
void blink(uint8_t count, uint32_t msOn, uint32_t msOff, const char * strOff = " ");
//function that handles time based modes and writes text to display
void handle(); //has to be run regularly when blink method is used
//TODO: blinkStrings and blink are very similar - optimize?
//TODO: add 'scroll string' method
private:
//--- variables ---
//config
max7219_t dev;
uint8_t posStart; //absolute position this display instance starts (e.g. multiple or very long 7 segment display)
uint8_t posCurrent;
displayMode mode = displayMode::NORMAL;
//blink modes
uint8_t count = 0;
char strOn[20];
char strOff[20];
bool state = false;
uint32_t msOn;
uint32_t msOff;
uint32_t timestampOn;
uint32_t timestampOff;
};