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单片机-红外计算器的主要内容,如果未能解决你的问题,请参考以下文章

毕业设计 基于51单片机的指纹红外密码电子锁

求51单片机红外摇控接收c程序,并在数码管上显示键值出来?

51单片机_红外线

51单片机学习笔记_14 红外遥控

4.4 51单片机-NEC红外线遥控器解码

Proteus仿真51单片机+红外测距仪(GP2D12)+ADC0809模数转换