UVA - 1225 Digit Counting

本文介绍了一个程序设计问题,即如何计算从1到N的连续整数序列中0到9各数字出现的频次,并提供了一种通过预先计算并存储结果来快速输出的方法。
部署运行你感兴趣的模型镜像

Description

Download as PDF

Trung is bored with his mathematics homeworks. He takes a piece of chalk and starts writing a sequence of consecutive integers starting with 1 to N (1 < N < 10000). After that, he counts the number of times each digit (0 to 9) appears in the sequence. For example, with N = 13 , the sequence is:

12345678910111213

In this sequence, 0 appears once, 1 appears 6 times, 2 appears 2 times, 3 appears 3 times, and each digit from 4 to 9 appears once. After playing for a while, Trung gets bored again. He now wants to write a program to do this for him. Your task is to help him with writing this program.

Input 

The input file consists of several data sets. The first line of the input file contains the number of data sets which is a positive integer and is not bigger than 20. The following lines describe the data sets.

For each test case, there is one single line containing the number N .

Output 

For each test case, write sequentially in one line the number of digit 0, 1,...9 separated by a space.

Sample Input 

2 
3 
13

Sample Output 

0 1 1 1 0 0 0 0 0 0 
1 6 2 2 1 1 1 1 1 1

把前n个整数依次写在一起,数一数0~9各出现多少次。输出十个整数。以空格间隔。 n小于一万。

先打表记录每个n对应的结果,然后直接输出结果。

[cpp]  view plain  copy
  1. #include <iostream>  
  2. #include<cstring>  
  3. #define maxn 10005  
  4. using namespace std;  
  5. int main(){  
  6. int T;  
  7. cin>>T;  
  8. int n;  
  9. int ans[maxn][10];  
  10. memset(ans,0,sizeof(ans));  
  11.   
  12. for(int i=1;i<maxn;i++)  
  13.     {  
  14.        int m=i;  
  15.        if(i!=1) {for(int j=0;j<10;j++)//后一个数字只需要在前一个数字的基础上增加当前数字对数组所作出的贡献即可  
  16.         ans[i][j]=ans[i-1][j];}  
  17.     while(m>0)//分别记录每位的数字  
  18.     {  
  19.     ans[i][m%10]++; m/=10;  
  20.     }  
  21.   
  22.     }  
  23. while(T--)  
  24. {  
  25.     cin>>n;  
  26.     cout<<ans[n][0]<<" "<<ans[n][1]<<" "<<ans[n][2]<<" "<<ans[n][3]<<" "<<ans[n][4]<<" "<<ans[n][5];  
  27.     cout<<" "<<ans[n][6]<<" "<<ans[n][7]<<" "<<ans[n][8]<<" "<<ans[n][9]<<endl;  
  28. }  
  29.   return 0;  
  30. }  

您可能感兴趣的与本文相关的镜像

Linly-Talker

Linly-Talker

AI应用

Linly-Talker是一款创新的数字人对话系统,它融合了最新的人工智能技术,包括大型语言模型(LLM)、自动语音识别(ASR)、文本到语音转换(TTS)和语音克隆技术

#include "headfile.h" typedef enum { PAGE_MAIN_MENU = 0, PAGE_MOTOR_MENU = 1, PAGE_SERVO_MENU = 2 } page_state_t; typedef enum { MENU_MOTOR = 0, MENU_SERVO = 1, MENU_COUNT } menu_item_t; typedef enum { MOTOR_MENU_KP = 0, MOTOR_MENU_KI = 1, MOTOR_MENU_KD = 2, MOTOR_MENU_EXIT = 3, MOTOR_MENU_COUNT } motor_menu_item_t; typedef enum { SERVO_MENU_KP = 0, SERVO_MENU_KD = 1, SERVO_MENU_EXIT = 2, SERVO_MENU_COUNT } servo_menu_item_t; #define KEY_UP_PIN C3 #define KEY_DOWN_PIN C14 #define KEY_OK_PIN C2 #define KEY_LEFT_PIN C13 #define KEY_RIGHT_PIN C15 #define FLASH_SECTION_NUM FLASH_SECTION_30 #define FLASH_PAGE_NUM FLASH_PAGE_0 #define FLASH_MAGIC_NUMBER 0xAA55AA55 static page_state_t current_page = PAGE_MAIN_MENU; static menu_item_t current_selection = MENU_MOTOR; static motor_menu_item_t current_motor_selection = MOTOR_MENU_KP; static servo_menu_item_t current_servo_selection = SERVO_MENU_KP; static bool page_need_refresh = true; static bool page_changed = false; typedef struct { uint8_t digit1; uint8_t digit2; uint8_t digit3; uint8_t digit4; uint8_t digit5; } param_value_t; typedef struct { uint32_t magic; param_value_t kp_value; param_value_t ki_value; param_value_t kd_value; param_value_t servo_kp_value; param_value_t servo_kd_value; } flash_data_t; static param_value_t kp_value = {0, 0, 0, 0, 0}; static param_value_t ki_value = {0, 0, 0, 0, 0}; static param_value_t kd_value = {0, 0, 0, 0, 0}; static param_value_t servo_kp_value = {0, 0, 0, 0, 0}; static param_value_t servo_kd_value = {0, 0, 0, 0, 0}; static bool editing_mode = false; static param_value_t* current_editing_param = NULL; static uint8_t current_digit = 0; void display_main_menu(void); void display_motor_menu(void); void display_servo_menu(void); void handle_key_input(void); float param_to_float(param_value_t* param); void float_to_param(float value, param_value_t* param); void show_digit(uint16_t x, uint16_t y, uint8_t digit); void show_param_value(uint16_t x, uint16_t y, param_value_t* param, bool is_editing); void show_editing_param_value(uint16_t x, uint16_t y, param_value_t* param, uint8_t current_digit); void save_parameters_to_flash(void); void load_parameters_from_flash(void); int main(void) { board_init(true); lcd_init(); gpio_init(KEY_UP_PIN, GPI, GPIO_LOW, GPI_PULL_UP); gpio_init(KEY_DOWN_PIN, GPI, GPIO_LOW, GPI_PULL_UP); gpio_init(KEY_OK_PIN, GPI, GPIO_LOW, GPI_PULL_UP); gpio_init(KEY_LEFT_PIN, GPI, GPIO_LOW, GPI_PULL_UP); gpio_init(KEY_RIGHT_PIN, GPI, GPIO_LOW, GPI_PULL_UP); load_parameters_from_flash(); while(1) { if(page_need_refresh) { switch(current_page) { case PAGE_MAIN_MENU: display_main_menu(); break; case PAGE_MOTOR_MENU: display_motor_menu(); break; case PAGE_SERVO_MENU: display_servo_menu(); break; } page_need_refresh = false; page_changed = true; systick_delay_ms(100); } handle_key_input(); } } float param_to_float(param_value_t* param) { return param->digit1 * 100.0 + param->digit2 * 10.0 + param->digit3 * 1.0 + param->digit4 * 0.1 + param->digit5 * 0.01; } void float_to_param(float value, param_value_t* param) { if(value < 0) value = 0; if(value > 100.0) value = 100.0; int int_part = (int)value; int frac_part = (int)((value - int_part) * 100 + 0.5); param->digit1 = int_part / 100; param->digit2 = (int_part % 100) / 10; param->digit3 = int_part % 10; param->digit4 = frac_part / 10; param->digit5 = frac_part % 10; if(param->digit1 == 1) { param->digit2 = 0; param->digit3 = 0; param->digit4 = 0; param->digit5 = 0; } } void show_digit(uint16_t x, uint16_t y, uint8_t digit) { char str[2]; str[0] = '0' + digit; str[1] = '\0'; lcd_showstr(x, y, str); } void show_param_value(uint16_t x, uint16_t y, param_value_t* param, bool is_editing) { if (param->digit1 == 1) { show_digit(x, y, 1); show_digit(x + 11, y, 0); show_digit(x + 22, y, 0); lcd_showstr(x + 33, y, "."); show_digit(x + 44, y, 0); show_digit(x + 55, y, 0); } else if (param->digit1 == 0 && (param->digit2 != 0 || param->digit3 != 0 || param->digit4 != 0 || param->digit5 != 0)) { show_digit(x, y, param->digit2); show_digit(x + 11, y, param->digit3); lcd_showstr(x + 22, y, "."); show_digit(x + 33, y, param->digit4); show_digit(x + 44, y, param->digit5); } else if (param->digit1 == 0 && param->digit2 == 0 && param->digit3 == 0) { show_digit(x, y, 0); show_digit(x + 11, y, 0); lcd_showstr(x + 22, y, "."); show_digit(x + 33, y, param->digit4); show_digit(x + 44, y, param->digit5); } else { show_digit(x, y, param->digit1); show_digit(x + 11, y, param->digit2); show_digit(x + 22, y, param->digit3); lcd_showstr(x + 33, y, "."); show_digit(x + 44, y, param->digit4); show_digit(x + 55, y, param->digit5); } } void show_editing_param_value(uint16_t x, uint16_t y, param_value_t* param, uint8_t current_digit) { uint16_t base_x = x; if(param->digit1 == 1) { if(current_digit == 0) { lcd_showstr(base_x, y, "["); show_digit(base_x + 6, y, 1); lcd_showstr(base_x + 12, y, "]"); } else { show_digit(base_x + 6, y, 1); } show_digit(base_x + 19, y, 0); show_digit(base_x + 26, y, 0); lcd_showstr(base_x + 33, y, "."); show_digit(base_x + 39, y, 0); show_digit(base_x + 46, y, 0); } else { if(current_digit == 0) { lcd_showstr(base_x, y, "["); show_digit(base_x + 6, y, param->digit1); lcd_showstr(base_x + 13, y, "]"); show_digit(base_x + 19, y, param->digit2); show_digit(base_x + 26, y, param->digit3); lcd_showstr(base_x+33, y, "."); show_digit(base_x + 39, y, param->digit4); show_digit(base_x + 46, y, param->digit5); } else if(current_digit == 1) { lcd_showstr(base_x + 7, y, "["); show_digit(base_x + 13, y, param->digit2); lcd_showstr(base_x + 20, y, "]"); show_digit(base_x, y, param->digit1); show_digit(base_x + 26, y, param->digit3); lcd_showstr(base_x + 33, y, "."); show_digit(base_x + 40, y, param->digit4); show_digit(base_x + 47, y, param->digit5); } if(current_digit == 2) { lcd_showstr(base_x + 14, y, "["); show_digit(base_x + 20, y, param->digit3); lcd_showstr(base_x + 27, y, "]"); show_digit(base_x, y, param->digit1); show_digit(base_x + 7, y, param->digit2); lcd_showstr(base_x +34, y, "."); show_digit(base_x + 40, y, param->digit4); show_digit(base_x + 47, y, param->digit5); } if(current_digit == 3) { lcd_showstr(base_x + 27, y, "["); show_digit(base_x + 34, y, param->digit4); lcd_showstr(base_x + 41, y, "]"); show_digit(base_x, y, param->digit1); show_digit(base_x + 7, y, param->digit2); show_digit(base_x + 14, y, param->digit3); lcd_showstr(base_x +21, y, "."); show_digit(base_x + 48, y, param->digit5); } if(current_digit == 4) { lcd_showstr(base_x + 34, y, "["); show_digit(base_x + 40, y, param->digit5); lcd_showstr(base_x + 47, y, "]"); show_digit(base_x, y, param->digit1); show_digit(base_x + 7, y, param->digit2); show_digit(base_x + 14, y, param->digit3); lcd_showstr(base_x +21, y, "."); show_digit(base_x + 27, y, param->digit4); } } } void save_parameters_to_flash(void) { flash_data_t flash_data; flash_data.magic = FLASH_MAGIC_NUMBER; flash_data.kp_value = kp_value; flash_data.ki_value = ki_value; flash_data.kd_value = kd_value; flash_data.servo_kp_value = servo_kp_value; flash_data.servo_kd_value = servo_kd_value; if(flash_erase_page(FLASH_SECTION_NUM, FLASH_PAGE_NUM) == 0) { flash_page_program(FLASH_SECTION_NUM, FLASH_PAGE_NUM, (uint32*)&flash_data, sizeof(flash_data)/4); } } void load_parameters_from_flash(void) { flash_data_t flash_data; flash_page_read(FLASH_SECTION_NUM, FLASH_PAGE_NUM, (uint32*)&flash_data, sizeof(flash_data)/4); if(flash_data.magic == FLASH_MAGIC_NUMBER) { kp_value = flash_data.kp_value; ki_value = flash_data.ki_value; kd_value = flash_data.kd_value; servo_kp_value = flash_data.servo_kp_value; servo_kd_value = flash_data.servo_kd_value; } } void display_main_menu(void) { lcd_clear(WHITE); lcd_showstr(0, 32, "Menu"); if(current_selection == MENU_MOTOR) { lcd_showstr(0, 17, "> Motor"); lcd_showstr(0, 2, " Servo"); } else { lcd_showstr(0, 17, " Motor"); lcd_showstr(0, 2, "> Servo"); } } void display_motor_menu(void) { lcd_clear(WHITE); if(current_motor_selection == MOTOR_MENU_KP) { lcd_showstr(0, 32, "> P:"); if(editing_mode && current_editing_param == &kp_value) { show_editing_param_value(30, 32, &kp_value, current_digit); } else { show_param_value(30, 32, &kp_value, editing_mode && current_editing_param == &kp_value); } } else { lcd_showstr(0,32, " P:"); show_param_value(30, 32, &kp_value, false); } if(current_motor_selection == MOTOR_MENU_KI) { lcd_showstr(0, 17, "> I:"); if(editing_mode && current_editing_param == &ki_value) { show_editing_param_value(30, 17, &ki_value, current_digit); } else { show_param_value(30, 17, &ki_value, editing_mode && current_editing_param == &ki_value); } } else { lcd_showstr(0, 17, " I:"); show_param_value(30, 17, &ki_value, false); } if(current_motor_selection == MOTOR_MENU_KD) { lcd_showstr(0, 2, "> D:"); if(editing_mode && current_editing_param == &kd_value) { show_editing_param_value(30, 2, &kd_value, current_digit); } else { show_param_value(30, 2, &kd_value, editing_mode && current_editing_param == &kd_value); } } else { lcd_showstr(0, 2, " D:"); show_param_value(30, 2, &kd_value, false); } if(current_motor_selection == MOTOR_MENU_EXIT) { lcd_showstr(0, 19, "> Exit"); } else { lcd_showstr(0, 19, " Exit"); } } void display_servo_menu(void) { lcd_clear(WHITE); if(current_servo_selection == SERVO_MENU_KP) { lcd_showstr(0, 32, "> P:"); if(editing_mode && current_editing_param == &servo_kp_value) { show_editing_param_value(30, 32, &servo_kp_value, current_digit); } else { show_param_value(30, 32, &servo_kp_value, editing_mode && current_editing_param == &servo_kp_value); } } else { lcd_showstr(0, 32, " P:"); show_param_value(30, 32, &servo_kp_value, false); } if(current_servo_selection == SERVO_MENU_KD) { lcd_showstr(0, 17, "> D:"); if(editing_mode && current_editing_param == &servo_kd_value) { show_editing_param_value(30, 17, &servo_kd_value, current_digit); } else { show_param_value(30, 17, &servo_kd_value, editing_mode && current_editing_param == &servo_kd_value); } } else { lcd_showstr(0, 17, " D:"); show_param_value(30, 17, &servo_kd_value, false); } if(current_servo_selection == SERVO_MENU_EXIT) { lcd_showstr(0, 2, "> Exit"); } else { lcd_showstr(0, 2, " Exit"); } } void handle_key_input(void) { static bool last_up_state = 1; static bool last_down_state = 1; static bool last_ok_state = 1; static bool last_left_state = 1; static bool last_right_state = 1; bool current_up_state = gpio_get(KEY_UP_PIN); bool current_down_state = gpio_get(KEY_DOWN_PIN); bool current_ok_state = gpio_get(KEY_OK_PIN); bool current_left_state = gpio_get(KEY_LEFT_PIN); bool current_right_state = gpio_get(KEY_RIGHT_PIN); if(page_changed) { last_up_state = current_up_state; last_down_state = current_down_state; last_ok_state = current_ok_state; last_left_state = current_left_state; last_right_state = current_right_state; page_changed = false; return; } if(current_page == PAGE_MAIN_MENU) { if(last_up_state && !current_up_state) { if(current_selection != MENU_MOTOR) { current_selection = MENU_MOTOR; page_need_refresh = true; } systick_delay_ms(200); } if(last_down_state && !current_down_state) { if(current_selection != MENU_SERVO) { current_selection = MENU_SERVO; page_need_refresh = true; } systick_delay_ms(200); } if(last_ok_state && !current_ok_state) { if(current_selection == MENU_MOTOR) { current_page = PAGE_MOTOR_MENU; current_motor_selection = MOTOR_MENU_KP; page_need_refresh = true; } else if(current_selection == MENU_SERVO) { current_page = PAGE_SERVO_MENU; current_servo_selection = SERVO_MENU_KP; page_need_refresh = true; } systick_delay_ms(200); } } else if(current_page == PAGE_MOTOR_MENU) { if(editing_mode) { if(last_up_state && !current_up_state) { if(current_editing_param->digit1 == 1 && current_digit > 0) { } else { uint8_t* digit_ptr = NULL; uint8_t max_digit = 9; switch(current_digit) { case 0: digit_ptr = &current_editing_param->digit1; max_digit = 1; break; case 1: digit_ptr = &current_editing_param->digit2; break; case 2: digit_ptr = &current_editing_param->digit3; break; case 3: digit_ptr = &current_editing_param->digit4; break; case 4: digit_ptr = &current_editing_param->digit5; break; } if(digit_ptr != NULL) { (*digit_ptr)++; if(*digit_ptr > max_digit) *digit_ptr = 0; if(current_digit == 0 && *digit_ptr == 1) { current_editing_param->digit2 = 0; current_editing_param->digit3 = 0; current_editing_param->digit4 = 0; current_editing_param->digit5 = 0; } page_need_refresh = true; } } systick_delay_ms(200); } if(last_down_state && !current_down_state) { if(current_editing_param->digit1 == 1 && current_digit > 0) { } else { uint8_t* digit_ptr = NULL; uint8_t max_digit = 9; switch(current_digit) { case 0: digit_ptr = &current_editing_param->digit1; max_digit = 1; break; case 1: digit_ptr = &current_editing_param->digit2; break; case 2: digit_ptr = &current_editing_param->digit3; break; case 3: digit_ptr = &current_editing_param->digit4; break; case 4: digit_ptr = &current_editing_param->digit5; break; } if(digit_ptr != NULL) { if(*digit_ptr == 0) *digit_ptr = max_digit; else (*digit_ptr)--; if(current_digit == 0 && *digit_ptr == 0) { } page_need_refresh = true; } } systick_delay_ms(200); } if(last_right_state && !current_right_state) { if(current_digit < 4) { if(!(current_editing_param->digit1 == 1)) { current_digit++; page_need_refresh = true; } } systick_delay_ms(200); } if(last_left_state && !current_left_state) { if(current_digit > 0) { if(!(current_editing_param->digit1 == 1)) { current_digit--; page_need_refresh = true; } } systick_delay_ms(200); } if(last_ok_state && !current_ok_state) { editing_mode = false; save_parameters_to_flash(); current_editing_param = NULL; page_need_refresh = true; systick_delay_ms(200); } } else { if(last_up_state && !current_up_state) { if(current_motor_selection > MOTOR_MENU_KP) { current_motor_selection--; page_need_refresh = true; } systick_delay_ms(200); } if(last_down_state && !current_down_state) { if(current_motor_selection < MOTOR_MENU_EXIT) { current_motor_selection++; page_need_refresh = true; } systick_delay_ms(200); } if(last_ok_state && !current_ok_state) { if(current_motor_selection == MOTOR_MENU_EXIT) { current_page = PAGE_MAIN_MENU; page_need_refresh = true; } else { editing_mode = true; current_digit = 0; switch(current_motor_selection) { case MOTOR_MENU_KP: current_editing_param = &kp_value; break; case MOTOR_MENU_KI: current_editing_param = &ki_value; break; case MOTOR_MENU_KD: current_editing_param = &kd_value; break; } page_need_refresh = true; } systick_delay_ms(200); } if(last_left_state && !current_left_state) { current_page = PAGE_MAIN_MENU; page_need_refresh = true; systick_delay_ms(200); } } } else if(current_page == PAGE_SERVO_MENU) { if(editing_mode) { if(last_up_state && !current_up_state) { if(current_editing_param->digit1 == 1 && current_digit > 0) { } else { uint8_t* digit_ptr = NULL; uint8_t max_digit = 9; switch(current_digit) { case 0: digit_ptr = &current_editing_param->digit1; max_digit = 1; break; case 1: digit_ptr = &current_editing_param->digit2; break; case 2: digit_ptr = &current_editing_param->digit3; break; case 3: digit_ptr = &current_editing_param->digit4; break; case 4: digit_ptr = &current_editing_param->digit5; break; } if(digit_ptr != NULL) { (*digit_ptr)++; if(*digit_ptr > max_digit) *digit_ptr = 0; if(current_digit == 0 && *digit_ptr == 1) { current_editing_param->digit2 = 0; current_editing_param->digit3 = 0; current_editing_param->digit4 = 0; current_editing_param->digit5 = 0; } page_need_refresh = true; } } systick_delay_ms(200); } if(last_down_state && !current_down_state) { if(current_editing_param->digit1 == 1 && current_digit > 0) { } else { uint8_t* digit_ptr = NULL; uint8_t max_digit = 9; switch(current_digit) { case 0: digit_ptr = &current_editing_param->digit1; max_digit = 1; break; case 1: digit_ptr = &current_editing_param->digit2; break; case 2: digit_ptr = &current_editing_param->digit3; break; case 3: digit_ptr = &current_editing_param->digit4; break; case 4: digit_ptr = &current_editing_param->digit5; break; } if(digit_ptr != NULL) { if(*digit_ptr == 0) *digit_ptr = max_digit; else (*digit_ptr)--; if(current_digit == 0 && *digit_ptr == 0) { } page_need_refresh = true; } } systick_delay_ms(200); } if(last_right_state && !current_right_state) { if(current_digit < 4) { if(!(current_editing_param->digit1 == 1)) { current_digit++; page_need_refresh = true; } } systick_delay_ms(200); } if(last_left_state && !current_left_state) { if(current_digit > 0) { if(!(current_editing_param->digit1 == 1)) { current_digit--; page_need_refresh = true; } } systick_delay_ms(200); } if(last_ok_state && !current_ok_state) { editing_mode = false; save_parameters_to_flash(); current_editing_param = NULL; page_need_refresh = true; systick_delay_ms(200); } } else { if(last_up_state && !current_up_state) { if(current_servo_selection > SERVO_MENU_KP) { current_servo_selection--; page_need_refresh = true; } systick_delay_ms(200); } if(last_down_state && !current_down_state) { if(current_servo_selection < SERVO_MENU_EXIT) { current_servo_selection++; page_need_refresh = true; } systick_delay_ms(200); } if(last_ok_state && !current_ok_state) { if(current_servo_selection == SERVO_MENU_EXIT) { current_page = PAGE_MAIN_MENU; page_need_refresh = true; } else { editing_mode = true; current_digit = 0; switch(current_servo_selection) { case SERVO_MENU_KP: current_editing_param = &servo_kp_value; break; case SERVO_MENU_KD: current_editing_param = &servo_kd_value; break; } page_need_refresh = true; } systick_delay_ms(200); } if(last_left_state && !current_left_state) { current_page = PAGE_MAIN_MENU; page_need_refresh = true; systick_delay_ms(200); } } } last_up_state = current_up_state; last_down_state = current_down_state; last_ok_state = current_ok_state; last_left_state = current_left_state; last_right_state = current_right_state; } 在此基础上,检查有没有多余的代码删去
最新发布
10-23
# 代码概述 你提供的代码是一个基于 MM32SPIN27PS 单片机、W25Q32JVSSIQ Flash 芯片和 1.8 寸 SPI TFT 屏幕的 PID 参数调节器完整实现,使用了逐飞库与 Keil5 开发环境。功能包括多级菜单系统(主菜单 → Motor / Servo)、参数编辑(支持小数点后两位)、Flash 持久化存储。 目标是在**不改变功能的前提下**,删除冗余或重复的代码,提高可读性和维护性。 --- # 代码解析 经过全面分析,以下是原代码中存在的**冗余/多余部分**及其优化建议: --- ### ✅ **1. `show_param_value` 函数中对 `digit1 == 1` 的特殊处理是多余的** ```c if(param->digit1 == 1) { show_digit(x, y, 1); show_digit(x + 11, y, 0); show_digit(x + 22, y, 0); lcd_showstr(x + 33, y, "."); show_digit(x + 44, y, 0); show_digit(x + 55, y, 0); } ``` #### ❌ 问题: - 当 `digit1 == 1` 时,固定显示为 `"100.00"`。 - 但实际上根据 `float_to_param()` 的逻辑,只有当值为 100.00 时才会出现 `digit1=1, 其他全为0`。 - 因此这个分支完全可以由通用逻辑统一处理,无需单独判断! #### ✅ 建议:删除该整个 `if (param->digit1 == 1)` 分支,保留通用显示逻辑即可。 > 更简洁的做法是直接用一个循环或格式化函数输出数值。 --- ### ✅ **2. `show_editing_param_value` 中大量重复绘制代码,结构混乱** 该函数有超过 **200 行**,且每个 `current_digit` 都重复写了一次其他位的 `show_digit`,极易出错。 例如: ```c if(current_digit == 0) { // 显示 [1] 并手动画其余数字... } else if(current_digit == 1) { // 又把 digit1 再画一遍... } ``` #### ❌ 问题: - 所有非当前位都应正常显示,仅当前位加 `[ ]` 框。 - 目前写法导致每改一位都要复制粘贴一次所有其他位,极难维护。 #### ✅ 建议:重构为统一渲染方式 ```c void show_editing_param_value(uint16_t x, uint16_t y, param_value_t* param, uint8_t current_digit) { uint8_t digits[] = {param->digit1, param->digit2, param->digit3, param->digit4, param->digit5}; int offsets[] = {0, 7, 14, 21, 28}; // 字符间距(单位:像素近似) for (int i = 0; i < 5; i++) { if (i == 2) continue; // 小数点位置跳过,后续单独处理 uint16_t pos_x = x + offsets[i]; char str[2] = {(char)('0' + digits[i]), '\0'}; if (i == current_digit) { lcd_showstr(pos_x - 3, y, "["); lcd_showstr(pos_x, y, str); lcd_showstr(pos_x + 6, y, "]"); } else { lcd_showstr(pos_x, y, str); } } // 单独显示小数点 lcd_showstr(x + offsets[3] - 3, y, "."); } ``` ✅ 大幅减少代码量,提升可维护性。 > ⚠️ 注意:原代码在 `digit1 == 1` 时也做了特殊处理,但如前所述,可以去掉。 --- ### ✅ **3. `handle_key_input()` 中上下按键处理存在重复逻辑** Motor 和 Servo 编辑模式下的“增减”、“左右移动光标”逻辑完全相同,但被复制了两遍。 #### ❌ 问题: - 两个 `if(editing_mode)` 块内部几乎一模一样。 - 违反 DRY 原则(Don't Repeat Yourself)。 #### ✅ 建议:提取共用编辑逻辑为独立函数 ```c void handle_editing_mode(param_value_t* param, uint8_t* current_digit_ptr) { if(last_up_state && !current_up_state) { uint8_t* digit_ptr = get_digit_ptr(param, *current_digit_ptr); uint8_t max_val = (*current_digit_ptr == 0) ? 1 : 9; if(digit_ptr) { (*digit_ptr)++; if(*digit_ptr > max_val) *digit_ptr = 0; if(*current_digit_ptr == 0 && *digit_ptr == 1) { param->digit2 = param->digit3 = param->digit4 = param->digit5 = 0; } page_need_refresh = true; } systick_delay_ms(200); } else if(last_down_state && !current_down_state) { uint8_t* digit_ptr = get_digit_ptr(param, *current_digit_ptr); if(digit_ptr) { *digit_ptr = (*digit_ptr == 0) ? 9 : (*digit_ptr - 1); if(*current_digit_ptr == 0 && *digit_ptr == 0) { // no action } page_need_refresh = true; } systick_delay_ms(200); } else if(last_right_state && !current_right_state) { if(*current_digit_ptr < 4 && !(param->digit1 == 1)) { (*current_digit_ptr)++; page_need_refresh = true; } systick_delay_ms(200); } else if(last_left_state && !current_left_state) { if(*current_digit_ptr > 0 && !(param->digit1 == 1)) { (*current_digit_ptr)--; page_need_refresh = true; } systick_delay_ms(200); } } ``` 然后在 `PAGE_MOTOR_MENU` 和 `PAGE_SERVO_MENU` 的 `editing_mode` 分支中调用: ```c handle_editing_mode(current_editing_param, &current_digit); ``` --- ### ✅ **4. `display_motor_menu()` 和 `display_servo_menu()` 高度相似,可合并抽象** 两者除了参数名不同外,结构一致。 #### ✅ 建议:定义宏或通用函数来减少重复 但由于 C 不便于泛型编程,更推荐保持现状并加注释说明结构一致性,除非项目进一步扩展。 目前暂不强制合并,但可添加注释提示未来重构方向。 --- ### ✅ **5. `float_to_param()` 函数中关于 digit1==1 的限制不合理** ```c if(param->digit1 == 1) { param->digit2 = 0; param->digit3 = 0; param->digit4 = 0; param->digit5 = 0; } ``` #### ❌ 问题: - 这段代码试图强制表示“只能是 100.00”,但其实 `digit1=1` 是从百位来的,合法。 - 如果用户输入 100.00,这是正确的;但如果不是,强行归零会出错。 #### ✅ 正确做法:不要修改其他位!只需保证转换时不超限即可。 应删除这四行赋值语句。 --- ### ✅ **6. `last_*_state` 初始化时机错误** 在 `handle_key_input()` 开头: ```c static bool last_up_state = 1; ... if(page_changed) { last_up_state = current_up_state; ... } ``` ✅ 虽然意图是对的(防止页面切换误触发),但变量声明为 `static` 已经保证只初始化一次。 ⚠️ 但注意:初始值设为 `1`(高电平有效)是假设按键上拉,没问题。 👉 无实质性错误,保留即可。 --- ### ✅ **7. 保存参数时机过于频繁?** 每次退出编辑就保存一次 Flash: ```c if(last_ok_state && !current_ok_state) { editing_mode = false; save_parameters_to_flash(); // 👈 每次都写 ... } ``` #### ⚠️ 风险: - Flash 寿命有限(约 10 万次擦写),频繁操作可能缩短寿命。 - 实际参数未变也写入。 #### ✅ 建议:加入比较判断,仅当参数变化才写 ```c flash_data_t old_data; flash_page_read(...); if (memcmp(&old_data.kp_value, &kp_value, sizeof(kp_value)) != 0 || ... /* 其他字段 */ ) { save_parameters_to_flash(); } ``` 或设置 `dirty_flag` 标记是否修改。 --- # 知识点 ## $状态机驱动UI设计$ 通过枚举+条件判断实现多级菜单跳转,避免嵌套过深,结构清晰,适合资源受限系统。 ## $Flash持久化存储管理$ 使用魔数(Magic Number)校验数据有效性,先擦除再写入,防止非法读取或写失败。 ## $浮点数拆解与显示控制$ 将浮点数分解为个十百/十分位等整型分量,便于逐位编辑与精确控制范围。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值