51单片机-红外计算器
Posted qq_38771744
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了51单片机-红外计算器相关的知识,希望对你有一定的参考价值。
51单片机-红外计算器
1、硬件:普中-A2开发板
使用哪些硬件资源?
1.1、LCD1602液晶显示器
1.2、红外接收头
1.3、红外遥控器
2、软件介绍:
2.1、共分为8个.c文件。
2.1.1、main.c 主要负责初始化,调用函数进行计算、显示
2.1.2、calculator.c 主要负责计算和字符输入
2.1.3、delay.c 延时函数
2.1.4、lcd1602.c 液晶屏驱动函数
2.1.5、time.c 定时器初始化、中断服务函数
2.1.6、uart.c 串口相关函数
2.1.7、Infrared.c 红外接收函数
2.1.8、EXIT.c 外部中断0初始化及中断服务函数
2.2、Infrared.c和EXIT一起,用来读取红外遥控按键键值,红外接收头接在P3 ^ 2引脚上,因此一旦外部中断0有下降沿,就进入红外接收函数,读取键值。
上代码
1、main.c
#include <REGX52.H>
#include <intrins.h>
#include <stdio.h>
#include <string.h>
#include "time.h"
#include "lcd1602.h"
#include "delay.h"
#include "typedef.h"
#include "key.h"
#include <stdlib.h>
#include "uart.h"
#include "calculator.h"
#include "infrared.h"
uint16_t time0Cnt = 0;//本工程未用到
//主函数
int main(void)
{
LcdInit();//LCD1602初始化
Timer0Init();//定时器初始化
Timer1Init();//定时器初始化
UART_Init(9600);//串口初始化
infrared_Init();//红外接收初始化
EA = 1;//使能所有中断
CalculatorInit(&calculator_s);//计算器结构体初始化
setDisplayAddr(0, 0);//从第一行第一列开始显示
printf("calculator");//上电先显示"calculator",提示这是计算器
while(1)
{
if(infraredValue != 0)//当接收到红外遥控器键值时
{
switch(getNumber(&calculator_s))//处理按键输入
{
case 0://显示运算结果
setDisplayAddr(0, 1);//显示在第2行开头
printf("%s", calculator_s.inputCharBuf);//LCD1602显示计算结果
break;
case 1://显示输入的内容
LcdWriteCom(0x01); //清屏
setDisplayAddr(0, 0);//显示在第一行开头
printf("%s", calculator_s.inputCharBuf);//LCD1602显示输入的字符串
break;
}
infraredValue = 0;
}
}
}
2、calculator.h
#ifndef __CALCULATOR_H_
#define __CALCULATOR_H_
#include <REGX52.H>
typedef struct
{
unsigned char inputCharBuf[16]; //输入的字符数组
unsigned int inputCharCnt; //输入的字符个数
unsigned int offset; //递归调用计算时偏移量
unsigned char errorFlag; //计算错误标志位 0:没有错误 1:被除数等于0 2:其他
float result; //运算结果
}Calculator_S;
extern Calculator_S calculator_s; //实例化计算器需要的结构体
unsigned char keyDeal(unsigned char keyValue);
void CalculatorInit(Calculator_S *s);
unsigned char getNumber(Calculator_S *s);
float calculator(Calculator_S *s);
float calculator_core(void)reentrant;
float my_atof(const char* pbuf);
void my_cal_atof(float* result, const char *pstr, unsigned int* index);
#endif
3、calculator.c
#include "calculator.h"
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <stdio.h>
#include <math.h>
#include "infrared.h"
#define PRINTF 0 //为1则打印log
Calculator_S calculator_s;//实例化计算器需要的结构体
//计算器结构体全部清零
void CalculatorInit(Calculator_S *s)
{
memset(s->inputCharBuf, 0x00, sizeof(s->inputCharBuf));
s->inputCharCnt = 0;
s->result = 0;
s->offset = 0;
s->errorFlag = 0;
}
//获取输入的数
unsigned char getNumber(Calculator_S *s)
{
unsigned char keyValue = 0xFF;
if(infraredValue != 0)//接收到新的键值
{
switch(infraredValue)
{
case 0x09://前括号
s->inputCharBuf[s->inputCharCnt++] = ')';
break;
case 0x07:
s->inputCharBuf[s->inputCharCnt++] = '(';
break;
case 0x43:
if(s->inputCharCnt > 0)//删除一个字符
{
s->inputCharCnt--;
s->inputCharBuf[s->inputCharCnt] = 0x00;
}
break;
case 0x0d://删除所有字符
s->inputCharCnt = 0;
memset(s->inputCharBuf, 0x00, sizeof(s->inputCharBuf));
break;
case 0x0c:
keyValue = '1';
break;
case 0x18:
keyValue = '2';
break;
case 0x5e:
keyValue = '3';
break;
case 0x40:
keyValue = '+';
break;
case 0x08:
keyValue = '4';
break;
case 0x1c:
keyValue = '5';
break;
case 0x5a:
keyValue = '6';
break;
case 0x19:
keyValue = '-';
break;
case 0x42:
keyValue = '7';
break;
case 0x52:
keyValue = '8';
break;
case 0x4a:
keyValue = '9';
break;
case 0x45:
keyValue = '*';
break;
case 0x44:
keyValue = '.';
break;
case 0x16:
keyValue = '0';
break;
case 0x15:
keyValue = '=';
break;
case 0x47:
keyValue = '/';
break;
default:
keyValue = 0xFF;
break;
}
if(keyValue != 0xFF)
{
if(keyValue == '=' || s->inputCharCnt >= 15)//输入的是=号
{
s->result = calculator(s);//进行计算
s->inputCharCnt = sprintf(s->inputCharBuf, "%.2f", calculator_s.result);//将计算结果放入输入数组中,while循环中进行显示
return 0;
}
else
{
/* 将输入的字符存入字符数组 */
s->inputCharBuf[s->inputCharCnt++] = keyValue;
return 1;
}
}
return 1;
}
return 2;//return 2 表示没有新的按键
}
float calculator(Calculator_S *s)
{
s->offset = 0;//计算偏移量回到输入数组开头
s->errorFlag = 0;//清除报警位
s->result = calculator_core();//调用计算函数进行计算
//清除状态标志位和输入数组
memset(s->inputCharBuf, 0x00, sizeof(s->inputCharBuf));
s->inputCharCnt = 0;
return s->result;//返回计算结果
}
//计算函数 reentrant表示可重入,(51单片机递归必须算好资源)
float calculator_core(void)reentrant
{
char sign = 0;//符号变量
float number[2] = {0, 0}; //输入的值转换成浮点数
char numberCnt = 0;//输入的数个数统计
sign = '+';//第一个数默认为+,因为-号会在转换成浮点数时转成负数
while(calculator_s.inputCharCnt > calculator_s.offset)//当输入字符个数大于偏移量时
{
/* 遇到左括号开始递归计算 */
if(calculator_s.inputCharBuf[calculator_s.offset] == '(')
{
#if PRINTF == 1
printf("递归入口\\r\\n");
#endif
calculator_s.offset++;
calculator_s.result = calculator_core();
}
/* i == 0时可以转换 */
if(calculator_s.offset == 0)
{
my_cal_atof(&calculator_s.result, (const char*)calculator_s.inputCharBuf, &calculator_s.offset);//字符串转float
}
/* 当本个字符是0-9数字,前一个字符不是0-9、.时,可以进行转换 */
else if(isdigit(calculator_s.inputCharBuf[calculator_s.offset])
&& (!isdigit(calculator_s.inputCharBuf[calculator_s.offset - 1]) && calculator_s.inputCharBuf[calculator_s.offset - 1] != '.'))
{
my_cal_atof(&calculator_s.result, (const char*)calculator_s.inputCharBuf, &calculator_s.offset);//字符串转float
}
/* 非数字或者到最后一个字符了 */
if(((calculator_s.inputCharBuf[calculator_s.offset] != ' ') && (!isdigit(calculator_s.inputCharBuf[calculator_s.offset])))
|| (calculator_s.offset == calculator_s.inputCharCnt - 1))
{
switch(sign)
{
case '+':
if(numberCnt == 2)
{
number[0] += number[1];
number[1] = calculator_s.result;
}
else
{
number[numberCnt++] = calculator_s.result;
}
break;
case '-':
if(numberCnt == 2)
{
number[0] += number[1];
number[1] = -calculator_s.result;
}
else
{
number[numberCnt++] = -calculator_s.result;
}
break;
case '*':
number[numberCnt - 1] *= calculator_s.result;//与前一个数相乘
break;
case '/':
if(calculator_s.result != 0)
{
number[numberCnt - 1] /= calculator_s.result;//与前一个数相除
}
else
{
calculator_s.errorFlag = 1;//标志被除数等于0
}
break;
case '%'://取余
number[numberCnt - 1] = number[numberCnt - 1] - (int)(number[numberCnt - 1] / calculator_s.result) * calculator_s.result;
break;
default:
break;
}
#if PRINTF == 1
printf("\\r\\nsign:%c,%.2f, %.2f\\r\\n", sign, number[0], number[1]);
#endif
sign = calculator_s.inputCharBuf[calculator_s.offset];//更新当前符号
}
/* 遇到右括号返回递归结果 */
if(calculator_s.inputCharBuf[calculator_s.offset] == ')')
{
#if PRINTF == 1
printf("递归出口\\r\\n");
#endif
calculator_s.offset++;//偏移量加1
break;
}
calculator_s.offset++;
}
#if PRINTF == 1
printf("result: %.2f\\r\\n", number[0] + number[1]);
#endif
return (number[0] + number[1]);
}
//本计算器专用字符串转浮点数函数,pstr是字符串指针,index为字符串坐标
void my_cal_atof(float* result, const char *pstr, unsigned int* index)
{
char sign = 1;//默认为正数
float point = 0.1;
*result = 0;
while (pstr[*index] < '0' || pstr[*index] > '9')
{
//去掉正负号影响
if (pstr[*index] == '-')
{
sign = 2;
}
else if(pstr[*index] == '+')
{
sign = 1;
}
(*index)++;
}
while (pstr[*index])
{
if (pstr[*index] == '.')
{
(*index)++;
while (pstr[*index] >= '0' && pstr[*index] <= '9')
{
*result += point * (pstr[*index] - '0');
point *= 0.1f;
(*index)++;
}
break;
}
else if (pstr[*index] >= '0' && pstr[*index] <= '9')
{
*result *= 10;
*result += pstr[*index] -'0';
}
else
{
break;
}
(*index)++;
}
(*index)--;
if(sign == 2)//负数
{
*result = -*result;
}
// #if PRINTF == 1
// printf("\\r\\nmy_cal_atof() = %.2f\\r\\n", *result);
// #endif
return;
}
4、delay.h
#ifndef __DELAY_H_
#define __DELAY_H_
#include "typedef.h"
#define MAIN_FOSC_DELAY 11059200UL //定义主时钟HZ
//延时n*1ms
void delay_ms(uint16_t ms);
void delay5us(void);
void delay_us(uint16_t us);
void delay_30us(void);
void delay_40us(以上是关于51单片机-红外计算器的主要内容,如果未能解决你的问题,请参考以下文章