0 引言
智能计算器是嵌入式开发的入门项目,本章使用STM 32芯片作为CPU,并将矩阵键盘和独立键盘作为输入外设,LCD1602作为显示屏,实现可输入的可视化智能计算器。
备注:最终生成的可执行HEX文件请点击这里。
1 基本原理
该项目中会用到的设备有STM 32芯片、4X4矩阵键盘、8位独立键盘和LCD1602显示屏。在实际运用中,可根据具体项目要求对这些硬件进行替换,可根据自己的需求改变,但项目的整体思路应该是基本不变的。
项目首先输入待计算的表达式,使用矩阵键盘用来输入数字0-9,独立键盘(8位)输入加减乘除、括号、等号等运算符,并在显示屏LCD1602上实时显示待计算的表达式。当输入“=”号,表达式输入完成,开始计算结果。结果计算完成,即可显示到LCD屏上。
1.1 实验接线
该项目使用普中科技单片机开发试验仪作为硬件设备。具体接线如下:
其中,JP11接JP4矩阵键盘,JP8接JP5独立键盘。
2 程序要点
实验利用STM32F10 CPU插件实现扫描键盘数字输入和独立键盘运算符输入以及LCD显示的智能计算器,并实现能够括号运算,加减乘除四则混合运算等较复杂计算的智能计算器。
实验程序主要思路是:使用uvision MDK4编译环境,首先配置系统时钟、NVIC,启动GPIOA、GPIOB模式时钟,设置GPIO I/O口,将LCD1602输出口、矩阵键盘输入口和独立键盘输入口初始化。初始化LCD1602。使用矩阵键盘输入数字,独立键盘输入符号(包括括号等),输入“=”结束输入。如果有输入错误,则清屏,重新输入。输入结束后调用计算器算法calculate()函数,计算输入的表达式结果,再调用result2char()函数将计算结果转换为LCD屏显示的字符,并显示在LCD显示屏上。
2.1 程序流程图
3 项目效果
3.1 两位数加法运算
3.2 三位数除法运算
3.3 带括号运算的加减乘除四则混合运算
4 程序代码
4.0 程序框架和编译环境
使用uvision MDK4编译环境,使用的库函数较少。项目文件框架如下:
只需要把main.c替换成4.3的完整程序代码,再按上图配置lib函数,即可编译成功。
如果配置不便,可以直接下载使用文章首部的 .HEX文件 。将该.HEX文件直接烧录到单片机中即可使用。
4.1 main()主函数
main()
{
j=1;
#ifdef DEBUG
//debug(); //在线调试使用
#endif
RCC_Configuration(); //系统时钟配置函数
NVIC_Configuration(); //NVIC配置函数
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB1Periph_TIM2 | RCC_APB2Periph_AFIO, ENABLE);//启动GPIO模块时钟
GPIO_PinRemapConfig(GPIO_Remap_SWJ_Disable,ENABLE); //把调试设置普通IO口
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All; //所有GPIO为同一类型端口
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //输出的最大频率为50HZ
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化GPIOA端口
GPIO_Init(GPIOB, &GPIO_InitStructure); //初始化GPIOB端口
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11 |GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15; //所有GPIO为同一类型端口
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; //开漏输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //输出的最大频率为50HZ
GPIO_Init(GPIOB, &GPIO_InitStructure); //初始化GPIOB端口
GPIO_Write(GPIOA,0xffff); //将GPIOA 16个端口全部置为高电平
GPIO_Write(GPIOB,0xffff); //将GPIOB 16个端口全部置为高电
lcd_init(); // 初始化LCD
delay(10);
while(1)
{
//输入表达式:矩阵键盘输入数字,独立键盘输入符号
while(flag_buf==0 && flag_fuhao2==0 && flag ==0)
{
keydown(); //矩阵按键检测
delay(20);
duli_keyscan(); //独立按键检测
delay(20);
lcd_wcmd_4bit(0x01);//清除LCD的内容
delay(2000);
LCD(); //实时显示按键的表达式
}
//如果有输入数字,将其显示在LCD屏上
if(flag_buf!=0)
{
dis1[j]=dis_buf+48;
}
//如果有输入符号,将其显示在LCD屏上
else if(flag_fuhao2!=0)
{
dis1[j]=fuhao;
}
//清除flag值
j++;
flag_buf=0;
flag_fuhao=0;
flag_fuhao2=0;
if(flag==1)
{
calculate(); //计算表达式的值
result2char();//将计算结果转化为字符串
dis2[0]=61; //输入“=”
flag_fuhao=0; //清空flag
flag=0;
}
//如果有清屏指令,则清除屏幕,重新开始输入
if(flag==2)
{
flag=0;
j=1;
for(m=0;m<16;m++)
{
dis1[m]=32;
}
for(m=0;m<16;m++)
{
dis2[m]=32;
}
delay(2000);
LCD();
}
}
}
4.2 主要变量和函数
// 主要变量
typedef unsigned char BYTE;
typedef unsigned char BOOL;
BYTE dis1[] = {
"H "}; //显示字符
BYTE dis2[] = {
" "};
BYTE dis_buf=0; //显示缓存
BYTE temp; //中间变量
BYTE key; //键顺序码
BYTE fuhao=32; //存储符号
BYTE flag=0; //判断是否结束
BYTE flag_buf=0; //缓存键值
BYTE flag_fuhao=0;//符号的flag
BYTE j,m,n; //循环计数索引
int i=0; //循环计数索引
int operand[15] = {
0}; //数字数组,初始化
int top_num = -1; //数组末尾
BYTE oper[15] = {
0}; //操作符数组,初始化
int top_oper = -1; //数组首部
BYTE* temp_p; // 数组指针
BYTE* str = dis1;//字符串指针
BYTE dest[15];//字符数组,存储结果
// 主要函数
void RCC_Configuration(void);//RCC初始化
void NVIC_Configuration(void); //NVIC初始化
void NOP(void); //延时周期
void Delay(vu32 nCount); //延时程序
void delay0(BYTE x); //延时子程序
void keyscan(void); // 矩阵键盘扫描子程序
void duli_keyscan(void); //独立按键扫描子程序
void keydown(void); //判断键盘键是否按下
void calculate(void); //判断键盘键是否按下
void result2char(void); //计算表达式的值
void LCD(void); //LCD显示
int insert_operand(int *operand , int * top_num ,BYTE num);//数据压入数据栈
int insert_oper (BYTE * oper , int *top_oper , char ch);//操作符压入符号栈
int compare(BYTE *oper , int *top_oper , BYTE ch);//比较操作服优先级
int deal_date(int *operand ,BYTE *oper ,int *top_num, int *top_oper);//进行数据运算
4.3 完整程序代码
(PS:实验代码有点长,其中有些注释不完整,但编译无错误。可结合以上的程序思路和主要变量、函数注释查看)
#include "stm32f10x_lib.h"
/********************************硬件接口定义*********************************/
#define RS GPIO_Pin_1 //P2^6;
#define RW GPIO_Pin_2 //P2^5;
#define EN GPIO_Pin_0 //P2^7;
/********************************宏定义*********************************/
#define LCD_RS(x) x ? GPIO_SetBits(GPIOB, RS): GPIO_ResetBits(GPIOB, RS)
#define LCD_RW(x) x ? GPIO_SetBits(GPIOB, RW): GPIO_ResetBits(GPIOB, RW)
#define LCD_EN(x) x ? GPIO_SetBits(GPIOB, EN): GPIO_ResetBits(GPIOB, EN)
/********************** 变量定义 ---------------------------*/
GPIO_InitTypeDef GPIO_InitStructure; //GPIO
ErrorStatus HSEStartUpStatus;
typedef unsigned char BYTE;
typedef unsigned char BOOL;
BYTE dis1[] = {
"H "};
BYTE d