【蓝桥杯单片机(27)】CT107D单片机--简易计算器

使用蓝桥杯CT107D单片机设计了一个简易计算器,具备加减乘除功能,通过1602显示屏显示结果,采用矩阵键盘进行输入。代码包括main函数、矩阵键盘及1602显示屏的C模块和头文件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

用蓝桥杯CT107D单片机做了一个简易计算器,能实现int型的加减乘除运算
使用1602显示屏作为显示器,矩阵键盘作为按键输入
本文的代码只是刚学单片机随性而为的,并没有考虑可读性,最近很多人因为这篇博客,订阅了专栏,实在诚惶诚恐,所以今天略作修改,如有进一步需要,可以私信我提供帮助

main函数

#include<Matrix_keyboard.h> //矩阵键盘
#include<1602.h> //液晶显示,
#include<stdio.h>
#include<stdlib.h>

#define  u8 unsigned char
#define  u16 unsigned int
#define  u32 unsigned long
#define  N 5

long n1, m1;
char ysf; //运算符
long digit[N];
char xdata sym[N];
u8 i = 0;	             //判断数字冲突
unsigned char xdata flag = 0; //判断运算符冲突
unsigned char xdata dengyuflag = 0;
unsigned char xdata index1 = 0;
unsigned char xdata index2 = 0;
u8 m = 16;
u8 x = 0;		//第二行
u8 y = 0;	 //第一行
void push1(long num) {
	digit[index1++] = num;
}
long gettop1() {
	return digit[index1 - 1];
}
void pop1() {
	index1--;
}
void clear1() {
	index1 = 0;
}
int feikong1() {
	if (index1 > 0)
		return 1;
	else return 0;
}


void push2(unsigned char num) {
	sym[index2++] = num;
}
char gettop2() {
	return sym[index2 - 1];
}
void pop2() {
	if (index2 > 0)
		index2--;
}
void clear2() {
	index2 = 0;
}
int feikong2() {
	if (index2 > 0)
		return 1;
	else return 0;
}

void Timer0Init(void)		//1毫秒@11.0592MHz
{
	AUXR |= 0x80;		//定时器时钟1T模式
	TMOD &= 0xF0;		//设置定时器模式
	TL0 = 0xCD;		//设置定时初值
	TH0 = 0xD4;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
	ET0 = 1;
	EA = 1;
}

u8 weishu(long n) {

	u8 cnt = 0;
	if (n < 0)cnt++;
	while (n) {
		n /= 10;
		cnt++;
	}
	return cnt;

}
u8 code symbol[] = "789/456*123-c0=+";
bit key_flag=1;
void main() {

	Timer0Init();
	LCD1602_Init( );
	while (1) {
		if(key_flag)
		{
			key_flag=0;
			m = read_keyboard();
			if (m != 16) {
			
			if (symbol[m] <= '9' && symbol[m] >= '0') {
				flag = 0;
				if (dengyuflag == 1) {
					y = 0;
					dengyuflag = 0;
					i = 1;
					pop1();
					push1(symbol[m] - '0');
					disnum_LCD(symbol[m] - '0', 0, y++);
				} else {
					disnum_LCD(symbol[m] - '0', 0, y++);
					if (i == 1) { //如果上次还是数字
						long st = gettop1();
						pop1();
						push1(st * 10 + symbol[m] - '0');
					}
					if (i == 0) { //如果上次是运算符
						i = 1;
						push1(symbol[m] - '0');
					}
				}

			} else if (symbol[m] == 'c') {
				if (dengyuflag == 1) {
					dengyuflag = 0;
				}
				x = 0;
				y = 0;
				Clear_LCD();
				clear1();
				clear2();
				disch_LCD('0', 0, 0);
			} else if (symbol[m] == '=') {
				if (flag == 1)
					pop2();
				  dengyuflag = 1;
				  flag = 1;
				  i = 0;
				if (feikong2() == 1) {
					m1 = gettop1();
					pop1();
					n1 = gettop1();
					pop1();
					ysf = gettop2();
					pop2();
					switch (ysf) {
						case '+':
							push1(m1 + n1);
							Clear_LCD();
							y = 0;
							disnum_LCD(n1 + m1, 0, 0);
							y += weishu(n1 + m1);
							break;
						case '-':
							push1(n1 - m1);
							Clear_LCD();
							y = 0;
							disnum_LCD(n1 - m1, 0, 0);
							y += weishu(n1 - m1);
							break;
						case '*':
							push1(m1 * n1);
							Clear_LCD();
							y = 0;
							disnum_LCD(n1 * m1, 0, 0);
							y += weishu(n1 * m1);
							break;
						case '/': {

							if (m1 == 0) {
								Clear_LCD();
								clear1();
								clear2();
								y = 0;
								disstr_LCD("NAN", 0, 0);
							} else {
								push1(n1 / m1);
								Clear_LCD();
								y = 0;
								disnum_LCD(n1 / m1, 0, 0);
								y += weishu(n1 / m1);
							}
						}
						break;
					}
				} else if (feikong2() == 0) {
					y = 0 + weishu(gettop1());
					Clear_LCD();
					disnum_LCD(gettop1(), 0, 0);
				}

			} else if (flag == 0) { //如果上次不是运算符
				flag = 1;
				disch_LCD(symbol[m], 0, y++);
				i = 0;
				if (feikong2() == 1) {
					m1 = gettop1();
					pop1();
					n1 = gettop1();
					pop1();
					ysf = gettop2();
					pop2();
					switch (ysf) {
						case '+':
							push1(m1 + n1);
							disnum_LCD(m1 + n1, 1, 0);
							break;
						case '-':
							push1(n1 - m1);
							disnum_LCD(n1 - m1, 1, 0);
							break;
						case '*':
							push1(m1 * n1);
							disnum_LCD(m1 * n1, 1, 0);
							break;
						case '/':
							if (m1 == 0) {
								Clear_LCD();
								clear1();
								clear2();
								y = 0;
								disstr_LCD("NAN", 0, 0);
								break;
							}
							push1(n1 / m1);
							disnum_LCD(n1 / m1, 1, 0);
							break;
					}
					push2(symbol[m]);
				}
				if (feikong2() == 0) {
					push2(symbol[m]);
				}


			} else if (flag == 1) { //上次也是运算符
				if (dengyuflag == 1) {
					dengyuflag = 0;
					disch_LCD(symbol[m], 0, y++);
					push2(symbol[m]);
				} else {
					disch_LCD(symbol[m], 0, y - 1);
					pop2();
					push2(symbol[m]);
				}
			}
		}
		}
	}	
}

void  Time0(void) interrupt 1 { //1ms中断一次
	static u8 i;
	if(++i==10){
	  i=0;
		key_flag=1;
	}
}

矩阵键盘.C模块

#include<Matrix_keyboard.h>
#include "STC15F2K60S2.H"

unsigned char read_keyboard(void)
{
  static unsigned char state=0;//state=0,进入第一次扫描;state=1;进入第二次扫描
  static unsigned char value=16;//按键返回值,直到按键释放后返回该值
  static unsigned char hang;//第一次获得哪一行?
  switch(state)
  {
    //进入第一次检测,检测哪一行被按下
    case 0:
	      P3=0X0F;P42=0;P44=0;//按键的行值置1,列值置0;
		  if(P3!=0X0F)//如果按键值改变了,就判断是哪一行
		  {
		    if(P30==0){hang=0;state=1;}//第一行
			  if(P31==0){hang=1;state=1;}//第二行
			  if(P32==0){hang=2;state=1;}//第三行
			  if(P33==0){hang=3;state=1;}//第四行
		  }else state=0;//无按键按下,停在第一次检测
		  break;
	//第二次检测,检测哪一列被按下
	case 1:
	       P3 = 0XF0;P42=1;P44=1;//列值置1,行值置0
		     if(P44==0)value=hang*4;//第一列四行的值,0 4 8 12
         if(P42==0)value=hang*4+1;//第二列四行的值,1 5 9 13
         if(P35==0)value=hang*4+2;//第三列四行的值,2 6 10 14
         if(P34==0)value=hang*4+3;//第四列四行的值,3 7 11 15
         break;
  }
  //等待按键释放
  P3=0X0F;P42=0;P44=0;//按键的行值置1,列值置0;
  if(state==1&&P3==0X0f)
  {
    state =0;
	  return value;
  }
  return 16;
}

矩阵键盘.h

#ifndef __Matrix_keyboard_H_
#define __Matrix_keyboard_H_
#include "STC15F2K60S2.H"
unsigned char read_keyboard( void );
#endif

1602.c显示模块

#include "STC15F2K60S2.H"
#include<1602.h>
#include<intrins.h>


#define Data P0
sbit LCDEN = P1^2;
sbit RS = P2^0;
sbit RW = P2^1;

void Delay1ms()		//@11.0592MHz
{
	unsigned char i, j;

	_nop_();
	_nop_();
	_nop_();
	i = 11;
	j = 190;
	do
	{
		while (--j);
	} while (--i);
}

void Delay5ms()		//@11.0592MHz
{
	unsigned char i, j;

	i = 54;
	j = 199;
	do
	{
		while (--j);
	} while (--i);
}

unsigned char Judg_LCD(void)//判断LCD忙/闲
{ //result忙闲标志,最高位D7为标志位,1忙0闲
  unsigned char result;
  Data = 0xff;//先置高电平,防止误判
  RS = 0;
  Delay5ms();
  RW = 1;//RS=0,RW = 1;忙标志和地址计数器写出
  LCDEN = 1;//使能信号开
  Delay5ms();
  result = Data & 0x80;//
  LCDEN = 0;//使能信号关
  return result;
}		    

void Wr_LCD(unsigned char m)//写入命令函数
{
   while(Judg_LCD()==1);
   RS = 0;
   Delay1ms();
   RW = 0; //RS = RW =0;命令寄存器写入
   LCDEN = 1;
   Delay1ms();
   Data = m;//写入数据
   Delay1ms();
   LCDEN = 0;
      
}
void Write_LCD(unsigned char Datval)//写入数据
{
  while(Judg_LCD()==1);
  RS = 1;
  Delay1ms();
  RW = 0;//RS = 1;RW =0;数据寄存器写入
  LCDEN = 1;
  Data = Datval;//写入数据
  Delay1ms();
  LCDEN = 0;
}
unsigned char RdCAdr(void)//读取当前光标地址
{
  unsigned char result;
  Data = 0xff;//先置高电平
  RS = 0;
  Delay5ms();
  RW = 1;//RS =0;RW=1;地址计数器读出
  LCDEN =1;
  Delay5ms();
  result = Data&0x7f;//去掉最高位忙闲标记,得低七位数据地址 
  LCDEN = 0;
  return result;
}
void retCadr(unsigned char add)
{
  Wr_LCD(0x80+add);
}
void LCDpos(unsigned char x,unsigned char y)
{ 
  unsigned char t;
  t = x?0x40:0x00;
  Wr_LCD(0x80+t+y);
}

void LCD1602_Init( )//1602初始化函数
{
   
   Wr_LCD(0x38);
   Wr_LCD(0x38);
   Wr_LCD(0x38);
   Wr_LCD(0x01);//清屏
   Wr_LCD(0x06);//光标自增,屏幕不动
   Delay1ms();
   Wr_LCD(0x0c);//开显示、关光标
   LCDpos(0,0);//从第一行第一个字符开始显示
   Delay5ms();
}
//从指定位置显示字符串
void disstr_LCD(unsigned char *p,unsigned char x,unsigned char y)//
{ 
  unsigned char i = 0;
  LCDpos(x,y);//指定坐标显示
  while(p[i]!='\0')
  { 
    Write_LCD(p[i]);
	i++;
	Delay5ms();
  }
}
void disch_LCD(unsigned char ch,unsigned char x,unsigned char y)//指定位置显示字符
{ 
  LCDpos(x,y);
  Write_LCD(ch);
  Delay5ms();
}
void disnum_LCD(long n,unsigned char x,unsigned char y)
{
    
    unsigned char i=0,j=0;
    unsigned char p[17],q[17]="          ";//清除第二行

	long m;
	if(n<0) m=-n;
	else m =n;//显示正数
	if(n==0)
	{
	 	disch_LCD('0',x,y);
		return;
	}
	while(m)
	 {
	   p[i++] = m%10+'0';
	   m=m/10;
	 }
	p[i--]='\0';
	if(n<0)
	  q[j++]='-';
	while(i)
	  q[j++] = p[i--];
	q[j++] = p[i];
	disstr_LCD(q,x,y);
}

void ch_LCD(unsigned ch)//当前位置显示字符
{ 
  Write_LCD(ch);
  Delay5ms();
}
void Clear_LCD(void)//清屏
{
  Wr_LCD(0x01);
}
void Return_LCD(void)//返回
{
  Wr_LCD(0x02);
}
void Backspace_LCD()//向左删除一个字符
{
  Wr_LCD(0X10);//光标左移
  Write_LCD(' ');//输出空格
  Wr_LCD(0X10);//光标左移
}
void Cursor_LCD(unsigned char d)//d=0,光标左移,d=1,右移
{ 
   if(d)
     Wr_LCD(0x14);//右移
   else
     Wr_LCD(0X10);//左移
}
void Screen_LCD(unsigned char d)//d=0,左移,d=1,右移
{
  if(d)
     Wr_LCD(0x1C);//右移
  else 
	 Wr_LCD(0x18);//左移
}
void OpCl_LCD(bit d)//LCD开关
{
  if(d==1)
    Wr_LCD(0x0f);
  else if(d==0)
    Wr_LCD(0x08);
}

1602.h

//在调用1602相关函数前,需要做1602的初始化
#ifndef _1602_H_
#define _1602_H_
#include "STC15F2K60S2.H"

void LCD1602_Init( );
void disstr_LCD(unsigned char *p,unsigned char x,unsigned char y);
void disnum_LCD(long n,unsigned char x,unsigned char y);
void disch_LCD(unsigned char ch,unsigned char x,unsigned char y);
void ch_LCD(unsigned ch);//当前位置显示字符
void Clear_LCD(void);//清屏
void Return_LCD(void);//返回
void Backspace_LCD();//向左删除一个字符
void Cursor_LCD(unsigned char d);//d=0,光标左移,d=1,右移
void Screen_LCD(unsigned char d);//d=0,左移,d=1,右移
void OpCl_LCD(bit d);//LCD开关
#endif
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小谦·

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值