51单片机自学笔记

目录

1,程序安装与运行

1,keil程序下载安装

2,烧录程序

2,常见错误

1,main.c(2): error C100: unprintable character 0xA0 skipped

2,error : syntax error near 'int'-for循环头部中尽量不要去定义变量

3,小案例程序

1,设置执行n边的流水LED灯

2,独立按键(设置独立按键控制流水LED灯实现)

3,动态数码管

4,LCD1602显示 

5,青花瓷歌曲



1,程序安装与运行

1,keil程序下载安装

下载程序:

链接:https://pan.baidu.com/s/18ffD5c3lSp1F1-xd8vnnjg 
提取码:2rft 
复制这段内容后打开百度网盘手机App,操作更方便哦

1,解压:

2,点击安装

3,直接next完后安装。

4,解压破解工具(注意如果解压文件夹下面没有文件的话,要关闭360等杀毒软件)

5,

以管理员的身份启动程序,,并且打开破解软件

将CID的内容复制粘贴到破解软件。

 

完成安装。 

2,烧录程序

文件接下直接可以运行

2,常见错误

1,main.c(2): error C100: unprintable character 0xA0 skipped

原因:keil里面出现了中文输入法时写的标点,例如: //lcm_w_word("abc您好");  不能出现全角的任何字符,包括空格在内 任何标点符号和空格都只能在英文的状态下输入,提示这个错误的话 把全角的字符或者标点替换一下即可。

全角字符和半角字符之间的区别:

一个汉字字符在电脑上要占两个英文字符的位置,当输入符号的时候全角的字符也是要占两个英文字符的位置,半角的只占一个字符也就是半个汉字的位置。这就是全角和半角的区

2,error : syntax error near 'int'-for循环头部中尽量不要去定义变量

 

3,小案例程序

1,设置执行n边的流水LED灯

 

#include <REGX52.H>//启动头文件
#include <INTRINS.H>//_nop_()命令需要的头文件
#include <intrins.h>//移位头文件	
// 延时函数
void delay(int n)
{
	while(n)
	{
		unsigned char i, j, k;
		_nop_();
		i = 8;
		j = 154;
		k = 122;
		do
		{
			do
			{
				while (--k);
			} while (--j);
		} while (--i);
		n--;
	}
}
void LED_flow(int n)//执行n次流水灯
{
	// 0表示接通 1表示断开
	int i;
	while(n>0)
	{
		for(i=0;i<8;i++)
		{
			P2=~(0x01<<i);	 //将1右移i位,然后将结果赋值到P2口
			delay(1); //大约延时450ms
		}
		n--;
	}
}
void main()
{
	LED_flow(1);//执行一次流水灯
	while(1)// 后面为卡住使灯灭
	{
			P2=0xFF;
	}
}

 

2,独立按键(设置独立按键控制流水LED灯实现)

 

#include <REGX52.H>//启动头文件
#include <INTRINS.H>//_nop_()命令需要的头文件
#include <intrins.h>//移位头文件	
// 延时函数
void delay_ms(int n)
{
	while(n)
	{
		unsigned char i, j;
		i = 12;
		j = 169;
		do
		{
			while (--j);
		} while (--i);
		n--;
	}
}
//流水LED灯
void LED_flow(int n)//执行n次流水灯
{
	// 0表示接通 1表示断开
	int i;
	while(n>0)
	{
		for(i=0;i<8;i++)
		{
			P2=~(0x01<<i);	 //将1右移i位,然后将结果赋值到P2口
			delay_ms(1000); //大约延时1s
		}
		n--;
	}
}
//按键控制流水LED灯
void indepence_button()
{
	int count=7;
	while(1)
	{
		if(P3_1==0)// K1键控制
		{
			delay_ms(20);
			while(P3_1==0);// 因为独立按键存在抖动的情况,故添加循环判断度过抖动期
			delay_ms(20);
			count++;
			if(count>=8)count=0;
			P2=~(0x01<<count);
			
			
		}
		if(P3_0==0)// K2键控制
		{
			delay_ms(20);
			while(P3_0==0);// 因为独立按键存在抖动的情况,故添加循环判断度过抖动期
			delay_ms(20);
			if(count==0)count=7;
			else count--;
			P2=~(0x01<<count);
		}
	}
}
void main()
{
	indepence_button();
}

 

3,动态数码管

 用于控制LED的选中,通过译码器可以减少接线口的使用。

 

 

#include <REGX52.H>//启动头文件
#include <INTRINS.H>//_nop_()命令需要的头文件
#include <intrins.h>//移位头文件	
// 延时函数
void delay_ms(int n)
{
	while(n)
	{
		unsigned char i, j;
		i = 12;
		j = 169;
		do
		{
			while (--j);
		} while (--i);
		n--;
	}
}
//流水LED灯
void LED_flow(int n)//执行n次流水灯
{
	// 0表示接通 1表示断开
	int i;
	while(n>0)
	{
		for(i=0;i<8;i++)
		{
			P2=~(0x01<<i);	 //将1右移i位,然后将结果赋值到P2口
			delay_ms(1000); //大约延时1s
		}
		n--;
	}
}
//按键控制流水LED灯
void indepence_button()
{
	int count=7;
	while(1)
	{
		if(P3_1==0)// K1键控制
		{
			delay_ms(20);
			while(P3_1==0);// 因为独立按键存在抖动的情况,故添加循环判断度过抖动期
			delay_ms(20);
			count++;
			if(count>=8)count=0;
			P2=~(0x01<<count);
			
			
		}
		if(P3_0==0)// K2键控制
		{
			delay_ms(20);
			while(P3_0==0);// 因为独立按键存在抖动的情况,故添加循环判断度过抖动期
			delay_ms(20);
			if(count==0)count=7;
			else count--;
			P2=~(0x01<<count);
		}
	}
}
//动态数码管显示
void dynamic_LED(int position,int number)
{
	
	unsigned char number_tool[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
					0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};//显示0~F的值
	if(position<=0||position>8)return;
	
	switch(position)
	{
		case 1:P2_2=0;P2_3=0;P2_4=0;break;
		case 2:P2_2=1;P2_3=0;P2_4=0;break;
		case 3:P2_2=0;P2_3=1;P2_4=0;break;
		case 4:P2_2=1;P2_3=1;P2_4=0;break;
		case 5:P2_2=0;P2_3=0;P2_4=1;break;
		case 6:P2_2=1;P2_3=0;P2_4=1;break;
		case 7:P2_2=0;P2_3=1;P2_4=1;break;
		case 8:P2_2=1;P2_3=1;P2_4=1;break;
	}
	P0=number_tool[number];
	delay_ms(1);//必须存在 否则会出现暗影的问题
}
void main()
{
	while(1)
	{
		dynamic_LED(8,5);
		P0=0x00;//消隐
		dynamic_LED(5,2);
		P0=0x00;//消隐
		dynamic_LED(1,0);
		P0=0x00;//消隐
	}
	
}

 

4,LCD1602显示 

LCD1602.c

#include <REGX52.H>

//引脚配置:
sbit LCD_RS=P2^6;
sbit LCD_RW=P2^5;
sbit LCD_EN=P2^7;
#define LCD_DataPort P0

//函数定义:
/**
  * @brief  LCD1602延时函数,12MHz调用可延时1ms
  * @param  无
  * @retval 无
  */
void LCD_Delay()
{
	unsigned char i, j;

	i = 2;
	j = 239;
	do
	{
		while (--j);
	} while (--i);
}

/**
  * @brief  LCD1602写命令
  * @param  Command 要写入的命令
  * @retval 无
  */
void LCD_WriteCommand(unsigned char Command)
{
	LCD_RS=0;
	LCD_RW=0;
	LCD_DataPort=Command;
	LCD_EN=1;
	LCD_Delay();
	LCD_EN=0;
	LCD_Delay();
}

/**
  * @brief  LCD1602写数据
  * @param  Data 要写入的数据
  * @retval 无
  */
void LCD_WriteData(unsigned char Data)
{
	LCD_RS=1;
	LCD_RW=0;
	LCD_DataPort=Data;
	LCD_EN=1;
	LCD_Delay();
	LCD_EN=0;
	LCD_Delay();
}

/**
  * @brief  LCD1602设置光标位置
  * @param  Line 行位置,范围:1~2
  * @param  Column 列位置,范围:1~16
  * @retval 无
  */
void LCD_SetCursor(unsigned char Line,unsigned char Column)
{
	if(Line==1)
	{
		LCD_WriteCommand(0x80|(Column-1));
	}
	else if(Line==2)
	{
		LCD_WriteCommand(0x80|(Column-1+0x40));
	}
}

/**
  * @brief  LCD1602初始化函数
  * @param  无
  * @retval 无
  */
void LCD_Init()
{
	LCD_WriteCommand(0x38);//八位数据接口,两行显示,5*7点阵
	LCD_WriteCommand(0x0c);//显示开,光标关,闪烁关
	LCD_WriteCommand(0x06);//数据读写操作后,光标自动加一,画面不动
	LCD_WriteCommand(0x01);//光标复位,清屏
}

/**
  * @brief  在LCD1602指定位置上显示一个字符
  * @param  Line 行位置,范围:1~2
  * @param  Column 列位置,范围:1~16
  * @param  Char 要显示的字符
  * @retval 无
  */
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char)
{
	LCD_SetCursor(Line,Column);
	LCD_WriteData(Char);
}

/**
  * @brief  在LCD1602指定位置开始显示所给字符串
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  String 要显示的字符串
  * @retval 无
  */
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String)
{
	unsigned char i;
	LCD_SetCursor(Line,Column);
	for(i=0;String[i]!='\0';i++)
	{
		LCD_WriteData(String[i]);
	}
}

/**
  * @brief  返回值=X的Y次方
  */
int LCD_Pow(int X,int Y)
{
	unsigned char i;
	int Result=1;
	for(i=0;i<Y;i++)
	{
		Result*=X;
	}
	return Result;
}

/**
  * @brief  在LCD1602指定位置开始显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~65535
  * @param  Length 要显示数字的长度,范围:1~5
  * @retval 无
  */
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
	unsigned char i;
	LCD_SetCursor(Line,Column);
	for(i=Length;i>0;i--)
	{
		LCD_WriteData(Number/LCD_Pow(10,i-1)%10+'0');
	}
}

/**
  * @brief  在LCD1602指定位置开始以有符号十进制显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:-32768~32767
  * @param  Length 要显示数字的长度,范围:1~5
  * @retval 无
  */
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length)
{
	unsigned char i;
	unsigned int Number1;
	LCD_SetCursor(Line,Column);
	if(Number>=0)
	{
		LCD_WriteData('+');
		Number1=Number;
	}
	else
	{
		LCD_WriteData('-');
		Number1=-Number;
	}
	for(i=Length;i>0;i--)
	{
		LCD_WriteData(Number1/LCD_Pow(10,i-1)%10+'0');
	}
}

/**
  * @brief  在LCD1602指定位置开始以十六进制显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~0xFFFF
  * @param  Length 要显示数字的长度,范围:1~4
  * @retval 无
  */
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
	unsigned char i,SingleNumber;
	LCD_SetCursor(Line,Column);
	for(i=Length;i>0;i--)
	{
		SingleNumber=Number/LCD_Pow(16,i-1)%16;
		if(SingleNumber<10)
		{
			LCD_WriteData(SingleNumber+'0');
		}
		else
		{
			LCD_WriteData(SingleNumber-10+'A');
		}
	}
}

/**
  * @brief  在LCD1602指定位置开始以二进制显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~1111 1111 1111 1111
  * @param  Length 要显示数字的长度,范围:1~16
  * @retval 无
  */
void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
	unsigned char i;
	LCD_SetCursor(Line,Column);
	for(i=Length;i>0;i--)
	{
		LCD_WriteData(Number/LCD_Pow(2,i-1)%2+'0');
	}
}

 LCD1602.h

#ifndef __LCD1602_H__
#define __LCD1602_H__

//用户调用函数:
void LCD_Init();
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char);
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String);
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length);
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);

#endif

 

小demo

#include <REGX52.H>//启动头文件
#include <INTRINS.H>//_nop_()命令需要的头文件
#include <intrins.h>//移位头文件	
#include "LCD1602.h"
// 延时函数
void delay_ms(int n)
{
	while(n)
	{
		unsigned char i, j;
		i = 12;
		j = 169;
		do
		{
			while (--j);
		} while (--i);
		n--;
	}
}
//流水LED灯
void LED_flow(int n)//执行n次流水灯
{
	// 0表示接通 1表示断开
	int i;
	while(n>0)
	{
		for(i=0;i<8;i++)
		{
			P2=~(0x01<<i);	 //将1右移i位,然后将结果赋值到P2口
			delay_ms(1000); //大约延时1s
		}
		n--;
	}
}
//按键控制流水LED灯
void indepence_button()
{
	int count=7;
	while(1)
	{
		if(P3_1==0)// K1键控制
		{
			delay_ms(20);
			while(P3_1==0);// 因为独立按键存在抖动的情况,故添加循环判断度过抖动期
			delay_ms(20);
			count++;
			if(count>=8)count=0;
			P2=~(0x01<<count);
			
			
		}
		if(P3_0==0)// K2键控制
		{
			delay_ms(20);
			while(P3_0==0);// 因为独立按键存在抖动的情况,故添加循环判断度过抖动期
			delay_ms(20);
			if(count==0)count=7;
			else count--;
			P2=~(0x01<<count);
		}
	}
}
//动态数码管显示
void dynamic_LED(int position,int number)
{
	
	unsigned char number_tool[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
					0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};//显示0~F的值
	if(position<=0||position>8)return;
	
	switch(position)
	{
		case 1:P2_2=0;P2_3=0;P2_4=0;break;
		case 2:P2_2=1;P2_3=0;P2_4=0;break;
		case 3:P2_2=0;P2_3=1;P2_4=0;break;
		case 4:P2_2=1;P2_3=1;P2_4=0;break;
		case 5:P2_2=0;P2_3=0;P2_4=1;break;
		case 6:P2_2=1;P2_3=0;P2_4=1;break;
		case 7:P2_2=0;P2_3=1;P2_4=1;break;
		case 8:P2_2=1;P2_3=1;P2_4=1;break;
	}
	P0=number_tool[number];
	delay_ms(1);//必须存在 否则会出现暗影的问题
}
//动态数码管显示520
void dynamic_LED_520()
{
		dynamic_LED(8,5);
		P0=0x00;//消隐
		dynamic_LED(5,2);
		P0=0x00;//消隐
		dynamic_LED(1,0);
		P0=0x00;//消隐
}
//LCD1602显示
void LCD1602()
{
	LCD_Init();
	LCD_ShowChar(1,1,'A');
	while(1)
	{
	}
}
void main()
{
	
	LCD1602();
	
}

 

5,青花瓷歌曲

#include <REG51.H>
#define uchar unsigned char
sbit beepIO=P1^5; //定义蜂鸣器端口为p1^5,根据单片机实际蜂鸣器实际接口改变
uchar m,n; //定义4个八度 每八度12分音律 共48音律
uchar code T[49][2]= {{0,0}, //定义音律49个二维数组
    {0xF9,0x1F},{0xF9,0x82},{0xF9,0xDF},{0xFA,0x37},{0xFA,0x8A},{0xFA,0xD8},{0xFB,0x23},{0xFB,0x68},{0xFB,0xAA},{0xFB,0xE9},{0xFC,0x24},{0xFC,0x5B},
    {0xFC,0x8F},{0xFC,0xC1},{0xFC,0xEF},{0xFD,0x1B},{0xFD,0x45},{0xFD,0x6C},{0xFD,0x91},{0xFD,0xB4},{0xFD,0xD5},{0xFD,0xF4},{0xFE,0x12},{0xFE,0x2D},
    {0xFE,0x48},{0xFE,0x60},{0xFE,0x78},{0xFE,0x86},{0xFE,0xA3},{0xFE,0xB6},{0xFE,0xC9},{0xFE,0xDA},{0xFF,0xEB},{0xFE,0xFA},{0xFF,0x09},{0xFF,0x17},
    {0xFF,0x24},{0xFF,0x30},{0xFF,0x3C},{0xFF,0x47},{0xFF,0x51},{0xFF,0x5B},{0xFF,0x64},{0xFF,0x6D},{0xFF,0x75},{0xFF,0x7D},{0xFF,0x84},{0xFF,0x8B}
};
uchar code music[][2]= {{0,4}, //定义曲谱数组,前数为音律,后数为音符节拍 ,要换歌改变简谱对应的音律号即可
    {0,1},{1,1},{3,1},{5,1},{6,1},{8,1},{10,1},{12,1},{13,1},//演示超低音八度 123457671
    {0,1},{13,1},{15,1},{17,1},{18,1},{20,1},{22,1},{24,1},{25,1},//演示低音八度12345671
    {0,1},{25,1},{27,1},{29,1},{30,1},{32,1},{34,1},{36,1},{37,1},//演示中音八度12345671
    {0,1},{37,1},{39,1},{41,1},{42,1},{44,1},{46,1},{48,2},//演示高音八度 1234567
    {0,4},{24,4},{24,4},{21,4},{19,4},{21,4},{14,8},{19,4},{21,4},{24,4},{21,4},{19,16},//记录菊花台简谱歌词:0553236 23532 天青色等烟雨 而我在等你
    {0,4},{24,4},{24,4},{21,4},{19,4},{21,4},{12,8},{19,4},{21,4},{24,4},{19,4},{17,16},//简谱歌词:0553235 23521 炊烟袅袅升起 隔江千万里
    {0,4},{17,4},{19,4},{21,4},{24,4},{26,4},{24,4},{22,4},{24,4},{21,4},{21,4},{19,4},{19,16},//简谱歌词:01235654 53322 在平地书刻你房间上的飘影
    {0,4},{17,4},{19,4},{17,4},{17,4},{19,4},{17,4},{19,4},{19,4},{21,8},{24,4},{21,4},{21,12},//简谱歌词:就当我为遇见你伏笔
    {0,4},{24,4},{24,4},{21,4},{19,4},{21,4},{14,8},{19,4},{21,4},{24,4},{21,4},{19,16}, //简谱歌词:0553236 23532 天青色等烟雨 而我在等你
    {0,4},{24,4},{24,4},{21,4},{19,4},{21,4},{12,8},{19,4},{21,4},{24,4},{19,4},{17,16}, //简谱歌词:0553235 23521 月色被打捞起 掩盖了结局
    {0,4},{17,4},{19,4},{21,4},{24,4},{26,4},{24,4},{22,4},{24,4},{21,4},{21,4},{19,4},{19,12},//简谱歌词:0123 5654 5332 25 322 11 如传世的青花瓷在独自美丽
    {12,4},{21,8},{19,8},{19,4},{17,20}, //简谱歌词:你眼带笑意
    {0xFF,0xFF}
}; //歌曲结尾标识


void delay(uchar p) //延时函数 无符号字符型变量
{
    uchar i,j; //定义无符号字符型变量J和I
    for(; p>0; p--) // 此处P值即主函数的n值节拍个数
        for(i=181; i>0; i--) //延时181*181个机器周期约35毫秒,即一个1/16节拍
            for(j=181; j>0; j--);
}




void T0_int() interrupt 1
{
    beepIO=!beepIO; //蜂鸣器翻转发声
    TH0=T[m][0];
    TL0=T[m][1];
//音律延时周期次数码表赋给定时寄存器作为计数初始值,每TH0TL0个机器周期触发蜂鸣器端口翻转,演奏出不同音符
}


void main()
{
    uchar i=0; //定义无符号字符型变量i,初始值为0
    TMOD=0x01;
    EA=1;
    ET0=1; //开启T0定时16位方式,总中断开启,开启T0外部中断请求
    while(1) //开始曲谱演奏,循环无限重复
    {
        m=music[i][0]; //将音律号赋值给m
        n=music[i][1]; //将节拍号赋值给n
        if(m==0x00) //如果音律号为0,
        {
            TR0=0;
            delay(n);
            i++;
        } //关闭计时器,延迟n拍,将循环数I加1 ,准备读下一个音符
        else if(m==0xFF) //否则如果音律数为FF
        {
            TR0=0;
            delay(30);
            i=0;
        } //开启节拍延时30个1/16节拍,歌曲停顿2秒,将循环数I置0
        else if(m==music[i+1][0]) // 否则如果把下一个音律号数给变量m
        {
            TR0=1;
            delay(n);
            TR0=0;
            i++;
        } //定时器0打开延迟n拍,关闭定时器T0,读下一个音符,循环数加1读下一个音律
        else //音符若不为零
        {
            TR0=1;
            delay(n);
            i++;
        }//打开定时器,延时n个1/16拍,循环数I加1 ,准备演奏下一个音符
    }
}

 

6,我和我的祖国 

#include <reg52.h>
sbit beep = P1^5;
unsigned char timer0H, timer0L, time;

//单片机晶振采用11.0592MHz
// 频率-半周期数据表 高八位     本软件共保存了四个八度的28个频率数据
code unsigned char FREQH[] = {
    0xF2, 0xF3, 0xF5, 0xF5, 0xF6, 0xF7, 0xF8,    //低音1234567
    0xF9, 0xF9, 0xFA, 0xFA, 0xFB, 0xFB, 0xFC, 0xFC,//1,2,3,4,5,6,7,i
    0xFC, 0xFD, 0xFD, 0xFD, 0xFD, 0xFE,            //高音 234567
    0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFF};   //超高音 1234567
// 频率-半周期数据表 低八位
code unsigned char FREQL[] = {
    0x42, 0xC1, 0x17, 0xB6, 0xD0, 0xD1, 0xB6,    //低音1234567
    0x21, 0xE1, 0x8C, 0xD8, 0x68, 0xE9, 0x5B, 0x8F, //1,2,3,4,5,6,7,i
    0xEE, 0x44, 0x6B, 0xB4, 0xF4, 0x2D,             //高音 234567
    0x47, 0x77, 0xA2, 0xB6, 0xDA, 0xFA, 0x16};   //超高音 1234567
//数据表           
code unsigned char song[] = {
5, 2, 2, 6, 2, 2, 5, 2, 2, 4, 2, 2, 3, 2, 2, 2, 2, 2, 1, 2, 6, 5, 1, 6, //我和我的祖国
1, 2, 2, 3, 2, 2, 1, 3, 2, 7, 2, 2, 6, 2, 3, 3, 2, 1, 5, 2, 12,			//一刻也不能分割
6, 2, 2, 7, 2, 2, 6, 2, 2, 5, 2, 2, 4, 2, 2, 3, 2, 2, 2, 2, 6, 6, 1, 6,	//无论我走到哪里
7, 1, 2, 6, 1, 2, 5, 1, 2, 5, 2, 2, 1, 2, 3, 2, 2, 1, 3, 2, 12,			//都唱出一首赞歌
5, 2, 2, 6, 2, 2, 5, 2, 2, 4, 2, 2, 3, 2, 2, 2, 2, 2, 1, 2, 6, 5, 1, 6,	//我歌唱每一座高山
1, 2, 2, 3, 2, 2, 1, 3, 2, 7, 2, 2, 2, 3, 3, 1, 3, 1, 6, 2, 12,			//我歌唱每一条河
1, 3, 2, 7, 2, 2, 6, 2, 2, 5, 2, 6,										//袅袅炊烟
6, 2, 2, 5, 2, 2, 4, 2, 2, 3, 2, 6,										//小小村落
7, 1, 4, 6, 1, 2, 5, 1, 4, 2, 2, 2, 1, 2, 12,							//路上一道辙 
8, 2, 2, 2, 3, 2, 3, 3, 2, 2, 3, 2, 8, 2, 2, 6, 2, 2, 7, 2, 2, 6, 2, 3, 3, 2, 1, 5, 2, 12,//我最亲爱的祖国
8, 2, 2, 2, 3, 2, 3, 3, 2, 2, 3, 2, 8, 2, 2, 6, 2, 2, 7, 2, 2, 5, 2, 3, 3, 2, 1, 6, 2, 12,//我永远紧依着你的心窝
5, 2, 2, 4, 2, 2, 3, 2, 2, 2, 2, 6, 7, 1, 2, 6, 1, 2, 5, 1, 2, 3, 2, 6,4, 2, 6, 2, 2, 4, 1, 2, 2,1, 2, 10,//你用你那母亲的脉搏和我诉说
};
//一个音符有三个数字。前为第几个音、中为第几个八度、后为时长(以半拍为单位)。
//6, 2, 3 分别代表:6, 中音, 3个半拍;
//5, 2, 1 分别代表:5, 中音, 1个半拍;

void t0int() interrupt 1         //T0中断程序,控制发音的音调
{
    TR0 = 0;                     //先关闭T0
    beep = !beep;          //输出方波, 发音
    TH0 = timer0H;               //下次的中断时间, 这个时间, 控制音调高低
    TL0 = timer0L;
    TR0 = 1;                     //启动T0
}

void delay(unsigned char t)     //延时程序,控制发音的时间长度
{
    unsigned char t1;
    unsigned long t2;
    for(t1 = 0; t1 < t; t1++)    //双重循环, 共延时t个半拍
      for(t2 = 0; t2 < 4000; t2++); //延时期间, 可进入T0中断去发音
    TR0 = 0;                        //关闭T0, 停止发音
}

void sing()                      //演奏一个音符
{
    TH0 = timer0H;               //控制音调
    TL0 = timer0L;
    TR0 = 1;                     //启动T0, 由T0输出方波去发音
    delay(time);                 //控制时间长度
}

void main(void)
{
    unsigned char k, i;
    TMOD = 1;                    //置T0定时工作方式1
    ET0 = 1;                     //开T0中断
    EA = 1;                      //开总中断
    while(1) 
	{
      i = 0;
      time = 1; 
      while(time) 
	  {
        k = song[i] + 7 * song[i + 1] - 1;//第i个是音符, 第i+1个是第几个八度
        timer0H = FREQH[k];      //从数据表中读出频率数值
        timer0L = FREQL[k];      //实际上, 是定时的时间长度
        time = song[i + 2];   //读出时间长度数值
        i += 3;
        sing();                  //发出一个音符
	  }  
    }  
}

 

  • 9
    点赞
  • 43
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

阿联爱学习

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

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

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

打赏作者

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

抵扣说明:

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

余额充值