stm32启动时用到的systeminit、__main说明

  1. 先运行systeminit函数,其功能:初始化时钟(SYSCLK, HCLK, PCLK2 and PCLK1 prescalers)、配置中断向量表(中断向量表的定位是在flash还是SRAM)
  2. 再运行__main函数:
  • 作用:Initialization of the execution environment and execution of the application
  • You can customize execution intialization by defining your own __main that branches to __rt_entry.
  • The entry point of a program is at __main in the C library where library code:
  • Copies non-root (RO(不会拷贝,官方提供和实际实践有出入) and RW) execution regions from their load addresses to their execution addresses. Also, if any data sections are compressed, they are decompressed from the load address to the execution address.
  • Zeroes ZI regions.
  • Branches to __rt_entry.
  • If you do not want the library to perform these actions, you can define your own __main that branches to __rt_entry。

 

  1. 再运行The library function __rt_entry() runs the program as follows:
  • Sets up the stack and the heap by one of a number of means that include calling __user_setup_stackheap(), calling __rt_stackheap_init(), or loading the absolute addresses of scatter-loaded regions.
  • Calls __rt_lib_init() to initialize referenced library functions, initialize the locale and, if necessary, set up argc and argv for main().This function is called immediately after__rt_stackheap_init() and is passed an initial chunk of memory to use as a heap. This function is the standard ARM C library initialization function and it must not be reimplemented.
  • Calls main(), the user-level root of the application.
  • From main(), your program might call, among other things, library functions.
  • Calls exit() with the value returned by main().


因为库函数里面的 ___main函数 和 ____rt_entry函数是弱函数,所有我们可以自己编写__main和__rt_entry

<think>嗯,用户想要一个基于STM32F103C8T6的简易计算器项目代码,需要包含主程序、4x4矩阵键盘驱动和LCD1602显示驱动,还要用学号3222005126作为密码,并实现四则运算功能。首先,我需要考虑如何组织这个项目,使用标准外设库V3.5.0的话,需要配置哪些外设呢? 首先,主程序的结构应该包括初始化部分,比如系统时钟、GPIO、键盘和LCD的初始化。然后进入主循环,不断扫描键盘输入,处理按键事件,更新显示,并执行计算逻辑。密码验证部分应该在计算器启动时或者进入特定模式时触发,比如当用户按下某个功能键时输入密码。 接下来是矩阵键盘的驱动。4x4矩阵通常需要4个行引脚和4个列引脚,设置为输入和输出。扫描方法一般是逐行输出低电平,检测列的电平变化来确定按下的键。需要消抖处理,比如延时检测。键值映射需要对应数字和运算符,比如0-9,加减乘除,等于,清除,以及密码确认键。 然后是LCD1602的驱动。STM32需要配置GPIO作为数据线和控制线(RS, RW, EN)。需要实现初始化函数、发送命令和数据的函数,以及显示字符串的函数。可能需要用到4位或8位模式,这里假设使用4位模式以节省IO口。显示部分需要处理输入的数字和运算结果,以及密码输入时的星号显示。 密码功能方面,用户输入学号3222005126作为密码。需要设计一个密码输入界面,当用户进入密码验证模式时,输入的数字显示为星号,输入完成后按确认键进行验证。密码正确后进入计算器主功能,否则提示错误。这里可能需要一个状态变量来记录当前是否处于密码输入模式。 四则运算的实现需要考虑表达式解析和计算。由于嵌入式资源有限,可能需要采用逆波兰算法或者简单的栈结构来处理运算符优先级。或者,也可以采用逐个处理,每次遇到运算符时先处理前一个运算符,但需要注意乘除优先于加减。例如,用户输入3+5*2,应该先计算5*2再加3,得到13。这需要维护一个操作数栈和运算符栈,或者实时计算。 另外,输入处理部分需要处理连续的数字输入,比如用户按1、2、3,则组合成123。当遇到运算符时,将当前数字保存,并记录运算符,然后继续输入下一个数字。等于号按下时执行运算并显示结果。清除键需要重置当前输入和状态。 代码结构方面,可能需要分为几个模块:main.c处理主循环和逻辑,keypad.c处理矩阵键盘扫描,lcd1602.c处理显示驱动,calculator.c处理运算逻辑和密码验证。头文件需要声明函数和全局变量。 需要考虑的问题包括:IO口的配置是否正确,矩阵键盘的扫描频率是否足够,LCD的时序是否符合要求,密码输入时的存储和比较是否安全(虽然这里可能只是简单比较字符串),四则运算的精度和错误处理(比如除以零)。 此外,标准外设库的使用需要注意初始化函数,比如RCC_APB2PeriphClockCmd使能相应的GPIO时钟,GPIO_InitTypeDef结构体的配置,以及可能的定时器用于消抖。中断可能不必要,因为矩阵键盘可以通过轮询方式扫描。 可能的错误点:矩阵键盘的行列接法错误导致扫描不到按键;LCD的初始化命令顺序不正确导致显示乱码;运算逻辑中的优先级处理错误导致计算结果不对;密码验证逻辑的条件判断错误。 测试步骤:先单独测试键盘驱动,确保每个按键能正确检测;再测试LCD显示,确保能显示字符;然后整合输入和显示,验证数字输入和运算符响应;接着加入密码功能,测试密码输入和验证流程;最后测试四则运算的正确性,尤其是乘除的优先级。 代码示例部分需要包含主函数的基本结构,键盘扫描函数,LCD驱动函数,以及运算处理的逻辑。由于代码量较大,可能需要分部分展示,并说明关键部分。同时需要注意注释,方便用户理解。 最后,用户可能需要相关的配置说明,比如如何连接矩阵键盘和LCD到STM32的引脚,如何下载程序到开发板,以及可能的常见问题解决方法。例如,如果LCD不显示,检查背光是否开启,对比度调节是否正确,数据线连接是否牢固等。</think>基于 STM32F103C8T6 的简易计算器实现可分为以下模块,代码需结合 STM32F10x_StdPeriph_Lib_V3.5.0 标准库开发: ### 一、工程结构 建议采用模块化设计: ``` Project/ ├── CMSIS/ ├── STM32F10x_StdPeriph_Lib/ ├── User/ │ ├── main.c │ ├── keypad.h │ ├── lcd1602.h │ └── calculator.h ``` ### 二、核心代码实现 #### 1. 主程序框架 (main.c) ```c #include "stm32f10x.h" #include "lcd1602.h" #include "keypad.h" #include "calculator.h" int main(void) { SystemInit(); Keypad_Init(); LCD_Init(); Calculator_State state = PASSWORD_MODE; char display_buf[17]; while(1) { uint8_t key = Keypad_Scan(); if(key != KEY_NONE) { Calculator_Handler(key, &state, display_buf); LCD_DisplayString(display_buf); } } } ``` #### 2. 矩阵键盘驱动 (keypad.h) ```c #define ROWS 4 #define COLS 4 typedef enum { KEY_0, KEY_1, ..., KEY_9, KEY_ADD, KEY_SUB, KEY_MUL, KEY_DIV, KEY_ENTER, KEY_CLEAR, KEY_NONE } Keypad_Key; void Keypad_Init(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); GPIO_InitTypeDef gpio; // 行引脚配置为推挽输出 gpio.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3; gpio.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(GPIOB, &gpio); // 列引脚配置为上拉输入 gpio.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7; gpio.GPIO_Mode = GPIO_Mode_IPU; GPIO_Init(GPIOB, &gpio); } Keypad_Key Keypad_Scan(void) { for(uint8_t row=0; row<ROWS; row++) { GPIO_Write(GPIOB, ~(1 << row)); Delay(10); // 消抖延时 uint16_t cols = GPIO_ReadInputData(GPIOB) >> 4; for(uint8_t col=0; col<COLS; col++) { if(!(cols & (1 << col))) { return key_map[row][col]; } } } return KEY_NONE; } ``` #### 3. LCD1602 驱动 (lcd1602.h) ```c void LCD_WriteCmd(uint8_t cmd) { GPIO_Write(GPIOC, cmd & 0xF0); // 高四位 GPIO_ResetBits(GPIOD, LCD_RS); LCD_Enable(); GPIO_Write(GPIOC, (cmd << 4) & 0xF0); // 低四位 LCD_Enable(); } void LCD_DisplayString(char *str) { LCD_WriteCmd(0x80); // 第一行起始地址 while(*str) { LCD_WriteData(*str++); } } ``` #### 4. 计算器逻辑 (calculator.h) ```c typedef enum {PASSWORD_MODE, CALC_MODE} Calculator_State; void Calculator_Handler(Keypad_Key key, Calculator_State *state, char *buf) { static char password[] = "3222005126"; static char input_buf[17]; switch(*state) { case PASSWORD_MODE: if(key == KEY_ENTER) { if(strcmp(input_buf, password) == 0) { *state = CALC_MODE; strcpy(buf, "Welcome!"); } } // 处理密码输入... break; case CALC_MODE: // 处理四则运算... break; } } ``` ### 三、关键实现要点 1. **四则运算算法**建议使用逆波兰表达式实现运算优先级处理[^1] 2. **密码验证**需采用循环缓冲区存储输入序列 3. **矩阵键盘扫描**采用行列扫描法,扫描周期建议≤50ms 4. **LCD1602 初始化**需严格按照时序要求配置4位总线模式
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值