秦皇的DIY MCU进程贴(大部分已完成,全部代码及视频在一楼链接)
第一个:流水灯程序 附上效果视频和源代码,望拍!!
20111129(001).rar
源代码:
#include<reg51.h>
#define uint unsigned int
#define LEDPORT P1
void Delay(uint time)
{
uint i,j;
for(i=0;i<300;i++)
for(j=0;j<time;j++);
}
void main()
{
uint i,temp1,temp2;
while(1)
{
//8个灯同一方向分别流水一次(亮一个灯)
LEDPORT=0x7f;
for(i=0;i<8;i++)
{
Delay(100);
LEDPORT=(LEDPORT>>1)|0x80;
}
LEDPORT=0xff;
Delay(100);
LEDPORT=0xfe;
for(i=0;i<8;i++)
{
Delay(100);
LEDPORT=(LEDPORT<<1)|0x01;
}
LEDPORT=0xff;
Delay(100);
//8个灯同一方向分别流水一次(灭一个灯)
LEDPORT=0x00;
Delay(100);
LEDPORT=0x80;
for(i=0;i<8;i++)
{
Delay(100);
LEDPORT=(LEDPORT>>1);
}
LEDPORT=0xff;
Delay(100);
LEDPORT=0x00;
Delay(100);
LEDPORT=0x01;
for(i=0;i<8;i++)
{
Delay(100);
LEDPORT=(LEDPORT<<1);
}
LEDPORT=0xff;
Delay(100);
//8个灯同一方向分别流水一次(跟随亮灯)
LEDPORT=0x7f;
for(i=0;i<8;i++)
{
Delay(100);
LEDPORT=(LEDPORT>>1);
}
LEDPORT=0xff;
Delay(100);
LEDPORT=0xfe;
for(i=0;i<8;i++)
{
Delay(100);
LEDPORT=(LEDPORT<<1);
}
LEDPORT=0xff;
Delay(100);
//8个灯同一方向分别流水一次(跟随灭灯)
LEDPORT=0x00;
Delay(100);
LEDPORT=0x80;
for(i=0;i<8;i++)
{
Delay(100);
LEDPORT=(LEDPORT>>1)|0x80;
}
LEDPORT=0x00;
Delay(100);
LEDPORT=0x01;
for(i=0;i<8;i++)
{
Delay(100);
LEDPORT=(LEDPORT<<1)|0x01;
}
LEDPORT=0xff;
Delay(100);
//4个灯相反方向分别流水一次(亮一个灯)
temp1=0x80;
temp2=0x01;
for(i=0;i<4;i++)
{
LEDPORT=~(temp1+temp2);
temp1=(temp1>>1);
temp2=(temp2<<1);
Delay(100);
}
LEDPORT=0xff;
Delay(100);
temp1=0x10;
temp2=0x08;
for(i=0;i<4;i++)
{
LEDPORT=~(temp1+temp2);
temp1=(temp1<<1);
temp2=(temp2>>1);
Delay(100);
}
LEDPORT=0xff;
Delay(100);
//4个灯相反方向分别流水一次(灭一个灯)
LEDPORT=0x00;
Delay(100);
temp1=0x80;
temp2=0x01;
for(i=0;i<4;i++)
{
LEDPORT=temp1+temp2;
temp1=(temp1>>1);
temp2=(temp2<<1);
Delay(100);
}
LEDPORT=0xff;
Delay(100);
LEDPORT=0x00;
Delay(100);
temp1=0x10;
temp2=0x08;
for(i=0;i<4;i++)
{
LEDPORT=temp1+temp2;
temp1=(temp1<<1);
temp2=(temp2>>1);
Delay(100);
}
//4个灯相反方向分别流水一次(跟随亮灯)
LEDPORT=0xff;
Delay(100);
temp1=0x80;
temp2=0x01;
for(i=0;i<4;i++)
{
LEDPORT=~(temp1+temp2);
temp1=(temp1>>1)|0x80;
temp2=(temp2<<1)|0x01;
Delay(100);
}
LEDPORT=0xff;
Delay(100);
temp1=0x10;
temp2=0x08;
for(i=0;i<4;i++)
{
LEDPORT=~(temp1+temp2);
temp1=(temp1<<1)|0x10;
temp2=(temp2>>1)|0x08;
Delay(100);
}
//4个灯相反方向分别流水一次(跟随灭灯)
LEDPORT=0xff;
Delay(100);
LEDPORT=0x00;
Delay(100);
temp1=0x80;
temp2=0x01;
for(i=0;i<4;i++)
{
LEDPORT=(temp1+temp2);
temp1=(temp1>>1)|0x80;
temp2=(temp2<<1)|0x01;
Delay(100);
}
LEDPORT=0x00;
Delay(100);
temp1=0x10;
temp2=0x08;
for(i=0;i<4;i++)
{
LEDPORT=(temp1+temp2);
temp1=(temp1<<1)|0x10;
temp2=(temp2>>1)|0x08;
Delay(100);
}
//快速闪烁20次
for(i=0;i<20;i++)
{
LEDPORT=0xff;
Delay(20);
LEDPORT=0x00;
Delay(20);
}
Delay(500);
}
}
附上效果视频和主要源代码,望拍!!
20111201.rar
void init(void)
{
TMOD=0x20;//定时器T1方式2
TH1=0xfd;
TL1=0xfd; //波特率9600
SCON=0x50;//串口方式1,允许接收
TR1=1; //启动定时器1
ES=1; //开串口中断
EA=1; //开总中断
}
//**************************************
void main(void)
{ uchar i;
init();
while(1)
{
Display(a-0x30);
if(RI)
{
RI=0;i=0;
while(as[i]!='\0'){SBUF=as[i];while(!TI);TI=0;i++;}
SBUF=b;while(!TI);TI=0;//接收到PC机数据之后返回
EA=1;
}
}
}
//*****************************************
void serial_serve(void) interrupt 4
{
a=SBUF;
b=a;
EA=0;
}
第三个:外部中断控制计数
附上效果视频和主要源代码,望拍!!
20111130.rar
void Time_init(void) //定时器初始化函数
{
TMOD=0x01;//模式选择定时器
TH1=0x3C;
TL1=0xB0; //定时器赋初值
ET1=0; //禁止T1中断
EX1=1; //开外部中断1
IT1=1; //中断为边沿触发
EA=1; //开总中断
}
void Int0(void) interrupt 2//外部中断0子程序
{
flag=~flag;
}
void main()
{
uint time,cnt;
Time_init();
while(1)
{
Display(time);
if(flag)
{
TR1=1;
if(TF1) //定时器溢出
{
TF1=0;
cnt++;
TH1=0x3C;
TL1=0xB0;
}
if(cnt==50)
{
cnt=0;
time++;
}
}
else TR1=0;
}
}
第四个:矩阵键盘PWM控制蜂鸣器和LED
附上效果视频和主要源代码,望拍!!
20111202.rar
uchar GetKey(void)//反极法获取键值
{
uint temp1,temp2;
P3=0x0f;
if(P3!=0x0f)
{
Delay(10);//去抖动
if(P3!=0x0f)
{
temp1=P3;
P3=0xf0;
if(P3!=0x0f)
{
Delay(10);//去抖动
if(P3!=0xf0)temp2=P3;
}
}
return (temp1|temp2);
}
return 0;
}
void Time_Init(void)
{
TEST=0;
TMOD=0x21 ;//定时器0选择方式1,定时器1选择方式2,
TH0=0xff ;
TL0=0x00 ; //频率调节
TH1=PWM ;
TL1=0x00 ; //脉宽调节
EA=1; //开总中断
ET0=1;
ET1=1; //开定时器中断
TR0=1 ; //启动定时器0
}
void main(void)
{
uchar k=0;
while(!(k=GetKey()))TEST=0;
Time_Init();
while(1)
{
Display(PWM);
switch(k)
{
case 0x7e/*S1*/:PWM=10;break;
case 0x7d/*S2*/:PWM=30;break;
case 0x7b/*S3*/:PWM=40;break;
case 0x77/*S4*/:PWM=60;break;
case 0xbe/*S5*/:PWM=80;break;
case 0xbd/*S6*/:PWM=90;break;
case 0xbb/*S7*/:PWM=110;break;
case 0xb7/*S8*/:PWM=130;break;
case 0xde/*S9*/:PWM=150;break;
case 0xdd/*S10*/:PWM=160;break;
case 0xdb/*S11*/:PWM=180;break;
case 0xd7/*S12*/:PWM=200;break;
case 0xee/*S13*/:PWM=210;break;
case 0xed/*S14*/:PWM=230;break;
case 0xeb/*S15*/:PWM=240;break;
case 0xe7/*S16*/:PWM=250;break;
default :break;
}
k=GetKey();
}
}
// 定时器0中断服务程序.
void timer0() interrupt 1 //控制低电平
{
TR1=0 ;
TH0=0xff ;
TL0=0x00;
TH1=PWM ;
TR1=1 ;
TEST=0; //启动输出
}
// 定时器1中断服务程序
void timer1() interrupt 3 //控制高电平
{
TR1=0 ;
TEST=1; //结束输出
}
第五个:DS1302实时时钟+1602显示
附上效果视频和主要源代码,望拍!!
20111201).rar
/********************************************************************
* 名称 : Run_DS1302(void)
* 功能 : 读出DS1302中的数据,并在液晶1602上进行显示
* 输入 : 无
* 输出 : 无
***********************************************************************/
void Run_DS1302(void)
{
uchar sec, min, hour, day, month, year;
v_W1302(0x8f, 0);
sec = bcdtodec(uc_R1302(0x81)); //读出DS1302中的秒
v_W1302(0x8f, 0);
min = bcdtodec(uc_R1302(0x83)); //读出DS1302中的分
v_W1302(0x8f, 0);
hour = bcdtodec(uc_R1302(0x85)); //读出DS1302中的小时
v_W1302(0x8f, 0);
day = bcdtodec(uc_R1302(0x87)); //读出DS1302中的日
v_W1302(0x8f, 0);
month = bcdtodec(uc_R1302(0x89)); //读出DS1302中的月
v_W1302(0x8f, 0);
year = bcdtodec(uc_R1302(0x8d)); //读出DS1302中的年
L1602_char(2, 6, hour / 10 % 10 + 48);
L1602_char(2, 7, hour % 10 + 48);
L1602_char(2, 8, '-');
L1602_char(2, 9, min / 10 % 10 + 48);
L1602_char(2, 10, min % 10 + 48);
L1602_char(2, 11, '-');
L1602_char(2, 12, sec / 10 % 10 + 48);
L1602_char(2, 13, sec % 10 + 48);
L1602_char(1, 8, year / 10 % 10 + 48);
L1602_char(1, 9, year % 10 + 48);
L1602_char(1, 10, '-');
L1602_char(1, 11, month / 10 % 10 + 48);
L1602_char(1, 12, month % 10 + 48);
L1602_char(1, 13, '-');
L1602_char(1, 14, day / 10 % 10 + 48);
L1602_char(1, 15, day % 10 + 48);
}
void Delay(uint time)
{
uchar i,j;
for(i=0;i<100;i++)
for(j=0;j<time;j++);
}
/********************************************************************
* 名称 : Main(void)
* 功能 : 主函数
* 输入 : 无
* 输出 : 无
***********************************************************************/
void Main(void)
{
int i;
L1602_init();
L1602_string(1,1,"DAYS 20");
L1602_string(2,1,"TIME");
if(uc_R1302(0xfd)!=0xff)Write_DS1302Init();
while(1)
{
if(KEY1==0)//年调整
{
Delay(100);
if(KEY1==0)
{
i=bcdtodec(YEAR);
i++;
YEAR= dectobcd(i);
SECOND=uc_R1302(0x81);
v_W1302(0x8e,0); //写保护关闭
v_W1302(0x80,SECOND|0x80); //秒寄存器最高设置1为暂时关闭计时功能,进入调整模式
v_W1302(0x8c,YEAR); //写入年
v_W1302(0x80,SECOND&0x7f); //退出调整模式,重新进入计时模式
v_W1302(0x8e,0x80); //写保护开启
}
}
if(KEY2==0)//月调整
{
Delay(100);
if(KEY2==0)
{
i=bcdtodec(MONTH);
i++;
if(i==13)i=1;
MONTH= dectobcd(i);
SECOND=uc_R1302(0x81);
v_W1302(0x8e,0); //写保护关闭
v_W1302(0x80,SECOND|0x80); //秒寄存器最高设置1为暂时关闭计时功能,进入调整模式
v_W1302(0x88,MONTH); //写入月
v_W1302(0x80,SECOND&0x7f); //退出调整模式,重新进入计时模式
v_W1302(0x8e,0x80); //写保护开启
}
}
if(KEY3==0)//日调整
{
Delay(100);
if(KEY3==0)
{
i=bcdtodec(DATE);
i++;
if(i>=31)i=1;
DATE= dectobcd(i);
SECOND=uc_R1302(0x81);
v_W1302(0x8e,0); //写保护关闭
v_W1302(0x80,SECOND|0x80); //秒寄存器最高设置1为暂时关闭计时功能,进入调整模式
v_W1302(0x86,DATE); //写入日
v_W1302(0x80,SECOND&0x7f); //退出调整模式,重新进入计时模式
v_W1302(0x8e,0x80); //写保护开启
}
}
if(KEY4==0)//时调整
{
Delay(100);
if(KEY4==0)
{
i=bcdtodec(HOUR);
i++;
if(i==24)i=0;
HOUR= dectobcd(i);
SECOND=uc_R1302(0x81);
v_W1302(0x8e,0); //写保护关闭
v_W1302(0x80,SECOND|0x80); //秒寄存器最高设置1为暂时关闭计时功能,进入调整模式
v_W1302(0x84,HOUR); //写入时
v_W1302(0x80,SECOND&0x7f); //退出调整模式,重新进入计时模式
v_W1302(0x8e,0x80); //写保护开启
}
}
Run_DS1302();
}
}
第六个:数码管倒计时(定时器中断)
附上效果视频和主要源代码,望拍!!
20111204.rar
本次实验实现定时器倒计时中断,S1按键设定时间+,S2按键设定时间-,时间以S为单位,按键S3开始倒计时,再次
按下时可以暂停倒计时,当时间到达时,八个LED灯闪烁,并且蜂鸣器间断鸣叫,发出警报。
void main(void)
{
uchar key;
P1_0=0;//关蜂鸣器
Time_init();
while(1)
{
Display(time);
key=GetKey();
switch(key)
{
case 0x0e/*S1*/:if(time<65536)time++;Delay(150);break;
case 0x0d/*S2*/:if(time>0)time--;Delay(150);break;
case 0x0b/*S3*/:flag=~flag;Delay(150);
if(flag)TR1=1;
else TR1=0;break;
default:break;
}
}
}
void Int(void) interrupt 3//定时器中断子程序
{
uchar cnt;
TH1=0x3C;
TL1=0xB0;
cnt++;
if(cnt==20)
{
cnt=0;
time--;
}
if(time==0)
{
while(1)
{
P1=~P1;
Delay(50);
}
}
}
第七个:DS18B20温度显示
附上效果视频和主要源代码,望拍!!
20111204.rar
20111204.rar
本次试验利用温度传感芯片DS18B20采集温度并分别在数码管和1602液晶上显示出来。
温度采集主要源程序:
unsigned int ReadTemperature(void)//读取温度
{
unsigned char a=0;
unsigned char b=0;
int t=0;
float tt=0;
Init_DS18B20();
WriteOneChar(0xCC); // 跳过读序号列号的操作
WriteOneChar(0x44); // 启动温度转换
Init_DS18B20();
WriteOneChar(0xCC); //跳过读序号列号的操作
WriteOneChar(0xBE); //读取温度寄存器
//连续读取两个字节数据
a=ReadOneChar(); //读低8位
b=ReadOneChar(); //读高8位
//将高低两个字节合成一个整形变量
//计算机中对于负数是利用补码来表示的
t=b;
t<<=8;
t=t|a;
//使用DS18B20的默认分辨率12位, 精确度为0.0625度, 即读回数据的最低位代表0.0625度
tt=t*0.0625;
t= tt*10+0.5; //放大10倍输出并四舍五入
return(t);
}
数码管显示主要源程序:
void Display(uint counter) //数码管显示函数
{
P0=number[counter/1000];P2=wei[4];Delay(1);//百位
P0=number[counter%1000/100];P2=wei[5];Delay(1); //十位
P0=number1[counter%1000%100/10];P2=wei[6];Delay(1); //个位
P0=number[counter%1000%100%10];P2=wei[7];Delay(1); //小数位
}
void main()
{
P1_0=0;//关蜂鸣器
Init_DS18B20();
WriteOneChar(0x33);
Init_DS18B20();
while(1) Display(ReadTemperature());
}
1602液晶显示主要源程序:
void main()
{
uint t;
P1_0=0;//关蜂鸣器
Init_DS18B20();
WriteOneChar(0x33);
Init_DS18B20();
L1602_init();
L1602_string(1,1,"--");
L1602_string(1,3,"EEPW MCU DIY");
L1602_string(1,15,"--");
L1602_string(2,15,".");
while(1)
{
t=ReadTemperature();
L1602_string(2,1,"Temper Now:");
L1602_char(2,12,number[t/1000]);
L1602_char(2,13,number[t%1000/100]);
L1602_char(2,14,number[t%1000%100/10]);
L1602_char(2,16,number[t%1000%100%10]);
}
}
附上效果视频和主要源代码,望拍!!
20111204.rar
本次实验利用外部存储芯片24C02来实现数据的传输演示,具体实验过程:矩阵键盘跳线帽接地端,两个数码管中,左边数码管显示的是在ROM中的实时数据,掉电易失,它是由按键S1增加和S2减少来获得的,范围是0-255,每按下一次S3按键,ROM中的数据就存储在了外部存储芯片24C02中了,24C02中的数据掉电非易失;而右边数码管显示的是实时外部存储芯片24C02相应地址中存储的数据,它是由按下S4按键来获得的,即每按下一次S4按键,单片机就从外部存储芯片24C02中的相应地址中读取数据,并在左边数码管中显示出来。
//******************
uchar rd_24c02(char a)//读数据
{
data uchar i,command;
SDA=1;_nop_();_nop_();_nop_();_nop_();
SCL=0;_nop_();_nop_();_nop_();_nop_();
start();
command=0xae;//芯片寻址写
shift8(command);
ack();
shift8(a); //发送地址
ack();
start();
command=0xaf;//芯片寻址读
shift8(command);
ack();
SDA=1;_nop_();_nop_();_nop_();_nop_();
for(i=0;i<8;i++)
{
com_data=com_data*2;
SCL=1;_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();
low_bit=SDA;
SCL=0;_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();
}//下降沿读出8位数据
stop();
return(com_data);
}
//*****************
void wr_24c02(char a,char b)//写数据
{
data uchar command;
_nop_();_nop_();_nop_();_nop_();_nop_();
SDA=1;_nop_();_nop_();_nop_();_nop_();
SCL=0;_nop_();_nop_();_nop_();_nop_();
start();
command=0xae;//芯片寻址写
shift8(command);
ack();
shift8(a);//写地址
ack();
shift8(b);//写数据
ack();
stop();
_nop_();_nop_();_nop_();_nop_();_nop_();
}
/******************************/
void main(void)
{
uchar key;
P1_0=0;//可读可写
while(1)
{
Display1(x);
Display2(y);
key=GetKey();
switch(key)
{
case 0x0e:if(x<255)x++;Delay(250);break;
case 0x0d:if(x>0)x--;Delay(250);break;
case 0x0b:wr_24c02(10,x);Delay(250);break;
case 0x07:y=rd_24c02(10);Delay(250);break;
default:break;
}
}
}
第九个:1602显示PS2键盘键值
附上效果视频和主要源代码,望拍!!
20111207.rar
本次实验利用PS2接口,把电脑键盘与单片机连接起来,每按下一个键盘按键,就在学习板的1602上显示出所按下的键。
void main(void)
{
P1_0=0;//关蜂鸣器
L1602_init(); //LCM初始化
L1602_string(1, 1, "--EEPW MCU DIY--");
L1602_string(2, 1, "The Key:");
IT0 = 0; //设外部中断0为低电平触发
EA = 1;
EX0 = 1; //开中断
do
{
if(BF) Decode(KeyV);
else EA = 1; //开中断
}
while(1);
}
void Keyboard_out(void) interrupt 0 //接收键盘数据
{
if ((IntNum > 0) && (IntNum < 9))
{
KeyV = KeyV >> 1; //因键盘数据是低>>高,所以右移
if (Key_Data) KeyV = KeyV | 0x80; //当键盘数据线为1时,赋1到最高位
}
IntNum++;
while (!Key_CLK); //等待CLK拉高
if (IntNum > 10)
{
IntNum = 0; //当中断11次后表示一帧数据收完,清变量准备下一次接收
BF = 1; //标识有字符输入完了
EA = 0; //关中断,等显示完后再开中断
}
}
void Decode(unsigned char ScanCode) //注意:如SHIFT+G为12H 34H F0H 34H F0H 12H,也就是说shift的通码+G的通码+shift的断码+G的断码
{
unsigned char TempCyc;
if (!Key_UP) //当键盘松开时
{
switch (ScanCode)
{
case 0xF0 : // 当收到0xF0,Key_UP置1表示键松开,断码开始
Key_UP = 1;break;
case 0x12 : // 左SHIFT按下
Shift = 1;break;
case 0x59 : // 右SHIFT按下
Shift = 1;break;
case 0xE0:SpecialFlag=1;break;//接收到的是特殊键值
default:
L1602_string(2,9," ");//键更新后刷新屏幕
if(SpecialFlag)//查特殊键值表
{
for(TempCyc = 0; (SpecialCode[TempCyc]!=ScanCode)&&(TempCyc<21); TempCyc++);
if (SpecialCode[TempCyc] == ScanCode) L1602_string(2, 9, SpecialString[TempCyc]);
SpecialFlag=0;
}
else if(!Shift) //如果SHIFT没按下
{
for (TempCyc = 0;(UnShiftedCode[TempCyc]!=ScanCode)&&(TempCyc<84); TempCyc++);
if (UnShiftedCode[TempCyc] == ScanCode) L1602_string(2, 9, UnShiftedString[TempCyc]);
}
else //按下SHIFT
{
for(TempCyc = 0; (ShiftedCode[TempCyc]!=ScanCode)&&(TempCyc<47); TempCyc++);
if (ShiftedCode[TempCyc] == ScanCode) L1602_string(2, 9, ShiftedString[TempCyc]);
}
break;
}
}
else
{
Key_UP = 0;
switch (ScanCode) //当键松开时不处理断码,如G 34H F0H 34H 那么第二个34H不会被处理
{
case 0x12 : // 左 SHIFT
Shift = 0;break;
case 0x59 : // 右 SHIFT
Shift = 0;break;
}
}
BF = 0; //标识字符处理完了
}
回复
有奖活动 | |
---|---|
【有奖活动】分享技术经验,兑换京东卡 | |
话不多说,快进群! | |
请大声喊出:我要开发板! | |
【有奖活动】EEPW网站征稿正在进行时,欢迎踊跃投稿啦 | |
奖!发布技术笔记,技术评测贴换取您心仪的礼品 | |
打赏了!打赏了!打赏了! |
打赏帖 | |
---|---|
vscode+cmake搭建雅特力AT32L021开发环境被打赏30分 | |
【换取逻辑分析仪】自制底板并驱动ArduinoNanoRP2040ConnectLCD扩展板被打赏47分 | |
【分享评测,赢取加热台】RISC-V GCC 内嵌汇编使用被打赏38分 | |
【换取逻辑分析仪】-基于ADI单片机MAX78000的简易MP3音乐播放器被打赏48分 | |
我想要一部加热台+树莓派PICO驱动AHT10被打赏38分 | |
【换取逻辑分析仪】-硬件SPI驱动OLED屏幕被打赏36分 | |
换逻辑分析仪+上下拉与多路选择器被打赏29分 | |
Let'sdo第3期任务合集被打赏50分 | |
换逻辑分析仪+Verilog三态门被打赏27分 | |
换逻辑分析仪+Verilog多输出门被打赏24分 |