Preparing for the Blue Bridge Cup -- actual combat of the embedded provincial competition of the 9th Blue Bridge Cup

Posted by brmcdani on Tue, 08 Mar 2022 13:11:16 +0100

Catalogue of series articles

Preparing for the Blue Bridge Cup (3) -- actual combat of the embedded provincial competition of the 8th Blue Bridge Cup
Preparing for the Blue Bridge Cup (2) -- actual combat of the embedded provincial competition of the seventh Blue Bridge Cup
Preparing for the Blue Bridge Cup (1) -- actual combat of the embedded provincial competition of the sixth Blue Bridge Cup

preface

The title of the 9th Blue Bridge Cup provincial competition is simpler than that of the 8th provincial competition, but I also have many small problems when I do it, which leads to jam. I also do a small review of what I have learned before. At the same time, the length of the keys of the provincial competition is also more rewarding than that of the first time. This time is still based on CT117E-M4 platform and developed with CUBEMX and keil.

1, The 9th provincial Blue Bridge Competition


2, Program flow chart

The program flow chart is drawn after the program is written, according to the logical relationship of the program I compiled. The logical relationship of this problem is not complex, and the idea is very clear.

3, CUBEMX configuration

The configurations here are all conventional configurations. Just match what you want according to the topic. Note here (also the error of my fan). Although there are I2C pins (PA6 and PA7) in the official EEPROM code, it needs to be configured in CUBEMX. The parameters can be configured by default. I read the code. I think it is because the pins in the routine are used directly without initialization. Therefore, if they are not configured in CUBEMX, they cannot be read and written to EEPROM.

4, Coding of each part

First, define the main function and variable:

/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "tim.h"
#include "gpio.h"
/* USER CODE BEGIN Includes */
#include "lcd.h"
#include "i2c.h"
#include "stdio.h"
#include "string.h"
/* USER CODE END Includes */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
struct Time{
    uint8_t hour;
    uint8_t min;
    uint8_t sec;
} TT_1;
/* USER CODE END PD */
int go_stop = 1; //Timing start / end flag bit
int time_cnt4 = 0; //Timer 4 count value
int long_pushB2 = 0;  //B2 key long press the flag bit
int long_pushB3 = 0;  //B3 key long press the flag bit
uint8_t str[20]; 
uint8_t str1[10];
uint8_t str2[20] = "      **          ";
uint8_t str3[20] = "         **       ";
uint8_t str4[20] = "            **    ";
unsigned char str5[10];
uint8_t re_loc = 1; //Storage location flag bits, 1 to 5
extern uint8_t time_cnt; //External variables, in xxxit c. Timer count value
extern uint8_t sec_08;  //External variables, in xxxit c. 0.8 second timing flag bit
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
uint8_t x24c02_read(uint8_t address); //EEPROM read function
void x24c02_write(unsigned char address,unsigned char info);  //EEPROM write function
void loc_change(void);  //Change storage location
void time_setting(void);  //Set time
void time_go_stop(void);  //Start / end timer
void led_flash(void);  //led flashing
void PWM_gen(void);  //PWM wave generation function
void res_time(void);//Storage time
void read_time(void);//Read time
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
int main(void)
{
  /* USER CODE BEGIN 1 */
    TT_1.hour = 0;
    TT_1.min = 0;
    TT_1.sec = 0;    
  /* USER CODE END 1 */
  HAL_Init();
  /* USER CODE BEGIN Init */
    I2CInit();
    LCD_Init();
    LCD_Clear(White);
    LCD_SetBackColor(White);
    LCD_SetTextColor(Black);    
  /* USER CODE END Init */
  /* Configure the system clock */
  SystemClock_Config();
  /* USER CODE BEGIN SysInit */
  /* USER CODE END SysInit */
  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_TIM2_Init();
  MX_TIM3_Init();
  MX_TIM4_Init();
  /* USER CODE BEGIN 2 */
  read_time();
  sprintf((char *)str,"      %02d:%02d:%02d",TT_1.hour,TT_1.min,TT_1.sec);
  LCD_DisplayStringLine(Line4,str);
  sprintf((char *)str1,"   No %d",re_loc);
  LCD_DisplayStringLine(Line1,str1);
  LCD_DisplayStringLine(Line7,"       Standby");  
  /* USER CODE END 2 */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
    /* USER CODE BEGIN 3 */
      loc_change();
      time_setting();
      time_go_stop();
      //PWM_gen();
      HAL_Delay(5);
  }
  /* USER CODE END 3 */
}

Next, at the end of the paper, the functions of each function are written according to each requirement

1. Realization of storage location change function

This function is relatively basic. It is only a short press, which is very routine. However, it should be noted that the EEPROM must be read again every time the storage location is changed. The code is as follows:

void loc_change(void)
{
    if(HAL_GPIO_ReadPin(KEY_B1_GPIO_Port,KEY_B1_Pin) == 0)
    {
        HAL_Delay(100);
        if(HAL_GPIO_ReadPin(KEY_B1_GPIO_Port,KEY_B1_Pin) == 0)//Judge whether the key is pressed
        {
            re_loc++;
            if(re_loc > 5)//Greater than 5 becomes 1, cycle
            {
                re_loc = 1;
            }
            read_time(); //If you change, you have to read the time again
            sprintf((char *)str1,"   No %d",re_loc); //The following are LCD display functions
            LCD_DisplayStringLine(Line1,str1);
            sprintf((char *)str,"      %02d:%02d:%02d",TT_1.hour,TT_1.min,TT_1.sec);
            LCD_DisplayStringLine(Line4,str);
        }
    }
}

2. Compilation of time setting function

This one is the most complex, involving the long and short pressing of keys, nesting of keys, etc. the logical relationship is relatively complex. Here I explain my idea: first, after pressing B2, the program enters a dead cycle, scans it to judge whether there is a key press, makes different reactions according to different keys, and calculates the time of key press at the same time, If it is greater than 0.8 seconds, nine is considered as long press and make corresponding actions. The general idea is like this. Next, on the program, I have more ideas and program notes. I should be able to understand my programming ideas.

void time_setting(void)
{
    int i = 0;
    if(HAL_GPIO_ReadPin(KEY_B2_GPIO_Port,KEY_B2_Pin) == 0)
    {
        HAL_Delay(150);
        if(HAL_GPIO_ReadPin(KEY_B2_GPIO_Port,KEY_B2_Pin) == 0)//Judge whether B2 is pressed
        {
            LCD_DisplayStringLine(Line5,str4);
            LCD_DisplayStringLine(Line7,"       Setting");//Display Setting
            while(1) //Enter the dead cycle
            {
                if(HAL_GPIO_ReadPin(KEY_B2_GPIO_Port,KEY_B2_Pin) == 0)
                {
                    HAL_Delay(100);
                    if(HAL_GPIO_ReadPin(KEY_B2_GPIO_Port,KEY_B2_Pin) == 0)//Judge whether B2 is pressed
                    {
                        i++;   //This is the flag bit for setting hours, minutes and seconds, 0 --- seconds, 1 --- minutes, 2 --- hours
                        if(i > 2)
                        {
                            i = 0;
                        } 
                        if( i == 0)
                        {
                            LCD_DisplayStringLine(Line5,str4);
                        }
                        if( i == 1)
                        {
                            LCD_DisplayStringLine(Line5,str3);
                        }
                        if( i == 2)
                        {
                            LCD_DisplayStringLine(Line5,str2);
                        }
                        while(HAL_GPIO_ReadPin(KEY_B2_GPIO_Port,KEY_B2_Pin) == 0)//If you keep pressing
                        {
                            HAL_TIM_Base_Start_IT(&htim2);//Turn on the timer
                            if(sec_08 == 1)//Judge whether the flag bit of 0.8 seconds is 1. If it is 1, it means that 0.8 seconds has arrived
                            {
                                long_pushB2 = 1;//Long press sign position 1
                                break;
                            }
                        }
                        HAL_TIM_Base_Stop_IT(&htim2);
                        time_cnt = 0;
                        sec_08 = 0;

                    }
                }
                if(HAL_GPIO_ReadPin(KEY_B3_GPIO_Port,KEY_B3_Pin) == 0)
                {
                    HAL_Delay(100);
                    if(HAL_GPIO_ReadPin(KEY_B3_GPIO_Port,KEY_B3_Pin) == 0)//Judge whether B3 is pressed
                    {
                        if(i == 0 )//The number of increases is determined according to the value of i
                        {
                            TT_1.sec++;
                        }
                        if(i == 1 )
                        {
                            TT_1.min++;
                        }
                        if(i == 2 )
                        {
                            TT_1.hour++;
                        }
                        sprintf((char *)str,"      %02d:%02d:%02d",TT_1.hour,TT_1.min,TT_1.sec);
                        LCD_DisplayStringLine(Line4,str);
                        while(HAL_GPIO_ReadPin(KEY_B3_GPIO_Port,KEY_B3_Pin) == 0)//If you keep pressing
                        {
                            HAL_TIM_Base_Start_IT(&htim2);//Turn on the timer
                            if(sec_08 == 1)//Judge whether the flag bit of 0.8 seconds is 1. If it is 1, it means that 0.8 seconds has arrived
                            {
                                long_pushB3 = 1;//Long press sign position 1
                                break;
                            }
                        }
                        HAL_TIM_Base_Stop_IT(&htim2);
                        time_cnt = 0;
                        sec_08 = 0;
                        while(long_pushB3 == 1 && HAL_GPIO_ReadPin(KEY_B3_GPIO_Port,KEY_B3_Pin) == 0)//Long press the flag bit to 1 and keep pressing it
                        {
                         if(i == 0 )//The fast-growing number is determined according to the value of i
                        {
                            TT_1.sec++;
                            HAL_Delay(95);
                            if(TT_1.sec == 60)
                            {
                                TT_1.sec = 0;
                                TT_1.min++;
                            }
                        }
                        if(i == 1 )
                        {
                            TT_1.min++;
                            HAL_Delay(95);
                            if(TT_1.min == 60)
                            {
                                TT_1.min = 0;
                                TT_1.hour++;
                            }
                        }
                        if(i == 2 )
                        {
                            TT_1.hour++;
                            HAL_Delay(95);
                            if(TT_1.hour == 24)
                            {
                                TT_1.hour = 0;
                            }                                
                        }
                        sprintf((char *)str,"      %02d:%02d:%02d",TT_1.hour,TT_1.min,TT_1.sec);//Update time
                        LCD_DisplayStringLine(Line4,str);
                    }
                    long_pushB3 = 0;
                    }  
                }
                if(HAL_GPIO_ReadPin(KEY_B4_GPIO_Port,KEY_B4_Pin) == 0 || long_pushB2 == 1)
                {
                    HAL_Delay(60);
                    if(HAL_GPIO_ReadPin(KEY_B4_GPIO_Port,KEY_B4_Pin) == 0 || long_pushB2 == 1)//Judge whether B4 is pressed or whether B2 is pressed for a long time
                    {
                        if(long_pushB2 == 0)//B2 no long press
                        {
                            LCD_DisplayStringLine(Line5,"                  ");
                            LCD_DisplayStringLine(Line7,"       Running");
                            go_stop = 1;//Start timer
                            break;
                        }
                        if(long_pushB2 == 1)//B2 long press
                        {
                            LCD_DisplayStringLine(Line5,"                  ");
                            LCD_DisplayStringLine(Line7,"       Standby");
                            long_pushB2 = 0;
                            res_time();//Save time in EEPROM
                            HAL_Delay(200);
                            break;
                        }
                    }
                }
            
           }
      }
  }
}

3. Timer start / end function

The logical relationship of this block is relatively simple, that is, press the key to start the timer, then press the stop timer, and long press to return to the initial page. There are also key nesting and key long and short press. However, I have encountered a problem in this area, because I use timer interrupt for countdown, but my time is defined by structure. It is difficult to use extern for external call. After checking the data, it is found that using extern for structure is very troublesome (I am too lazy), so I use interrupt callback function:

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)

It's hard to knock this with keil. I don't feel this when I use vscode and clion. I won't say more about timer interrupt. Go directly to the code:

void time_go_stop(void)
{
    if(HAL_GPIO_ReadPin(KEY_B4_GPIO_Port,KEY_B4_Pin) == 0)
        {
                    HAL_Delay(150);
                    if(HAL_GPIO_ReadPin(KEY_B4_GPIO_Port,KEY_B4_Pin) == 0)//Judge whether the key B4 is pressed
                    {
                        while(1)//Enter the dead cycle
                        {
                            if(HAL_GPIO_ReadPin(KEY_B4_GPIO_Port,KEY_B4_Pin) == 0)
                            {
                                HAL_Delay(50);
                                if(HAL_GPIO_ReadPin(KEY_B4_GPIO_Port,KEY_B4_Pin) == 0)//Judge whether key 4 is pressed
                                {
                                    go_stop = 1-go_stop;
                                    while(HAL_GPIO_ReadPin(KEY_B4_GPIO_Port,KEY_B4_Pin) == 0)//If you keep pressing
                                    {
                                        HAL_TIM_Base_Start_IT(&htim2);
                                        if(sec_08 == 1)//Judge whether the flag bit of 0.8 seconds is 1. If it is 1, it means that 0.8 seconds has arrived
                                        {
                                            long_pushB4 = 1;//Judge whether the flag bit of 0.8 seconds is 1. If it is 1, it means that 0.8 seconds has arrived
                                            break;
                                        }
                                    }
                                    HAL_TIM_Base_Stop_IT(&htim2);
                                    time_cnt = 0;
                                    sec_08 = 0;
                                }
                            }
                            if(long_pushB4 == 1)//Long press to exit and return to the initial page
                            {
                                long_pushB4 = 0;
                                LCD_DisplayStringLine(Line7,"       Standby");
                                sprintf((char *)str,"      %02d:%02d:%02d",TT_1.hour,TT_1.min,TT_1.sec);
                                LCD_DisplayStringLine(Line4,str);
                                HAL_Delay(150);
                                break;
                            }
                            if(go_stop == 1)//Timer start
                            {
                                LCD_DisplayStringLine(Line7,"       Running");
                                HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_1);//Start PWM
                                led_flash();//On LED flashing
                                HAL_TIM_Base_Start_IT(&htim4);//Start timer TIM4
                                if(TT_1.hour == 0 && TT_1.min==0 && TT_1.sec == 0)
                                {
                                    HAL_TIM_Base_Start_IT(&htim4);
                                    go_stop = 0;
                                }
                                sprintf((char *)str,"      %02d:%02d:%02d",TT_1.hour,TT_1.min,TT_1.sec);
                                LCD_DisplayStringLine(Line4,str);
                            }
                            if(go_stop == 0)//Timer end
                            {
                                LCD_DisplayStringLine(Line7,"       Pause  ");
                                HAL_TIM_Base_Stop_IT(&htim4);
                                time_cnt4 = 0;
                                HAL_TIM_PWM_Stop(&htim3,TIM_CHANNEL_1);
                                HAL_GPIO_WritePin(LED_GPIO_Port,LED_Pin,GPIO_PIN_SET);
                                HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);
                                HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);
                            }
                        }
                    }
        }
}

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)//Interrupt callback function
{
    
    if(htim -> Instance == htim4.Instance)//If TIM4 is interrupted
    {
        time_cnt4++;
        if(time_cnt4 == 100)//One second counts
        {
            TT_1.sec--;
            if(TT_1.sec == 255)//uint8 type 0-1 = = 255, complement operation
            {
                TT_1.sec = 59;
                TT_1.min--;
            }
            if(TT_1.min == 255)
            {
                TT_1.min = 59;
                TT_1.hour--;
            }
            time_cnt4 = 0;
        }
    }
}

So far, the main code of the project has been written, and there is no problem in the actual measurement. The problem is satisfactorily ended.

summary

  1. When using EEPROM, you need to configure the corresponding I2C pin in CUBEMX, because there is no initialization of IO port in the official routine.
  2. When continuously writing / reading EEPROM data, a delay of 10ms is required between two operations. It should be that I2C communication will respond. Without delay, it is impossible to write / read continuously.
  3. I'm not familiar with the external call of the structure, so I need to check more materials to learn.

Download of engineering documents of the 9th provincial competition: Download link

Topics: C Embedded system stm32