当前位置:首页 > 单片机 > 单片机
[导读]一.原理和功能介绍1.PROTEUS模拟的效果图如下:我简要介绍一下系统的组成及各部分的功能本系统主要有五部分构成:1.显示和键盘显示采用的是最常用最便宜的1602液晶,内藏HD44780,且内含简单字库.指令简单,容易上手键盘部

一.原理和功能介绍

1.PROTEUS模拟的效果图如下:

我简要介绍一下系统的组成及各部分的功能

本系统主要有五部分构成:

1.显示和键盘

显示采用的是最常用最便宜的1602液晶,内藏HD44780,且内含简单字库.指令简单,容易上手

键盘部分由7个按键和一个电位器旋钮组成系统的输入部分.(如图)

2.运算处理单元

本系统的所有操作都由PIC16F877A单片机完成(选择他的理由:端口多,不需扩展)

3.存储单元

主要由一片24C01的1K内存的EEPROM完成,此芯片与单片机通过I2C总线通信,具有占有端口少的优点.

4.输出控制单元

由一片光耦和一个双向晶闸管组成.单片机输出的脉冲通过控制光耦的通断控制双向晶闸管的通断,从而控制电灯的亮度.

5.时钟单元

这是一个附加单元,对本系统无关键作用,只是为了增加附加值.有一片DS1302时钟芯片和一个32768Hz的晶振组成

功能说明

1.一上电,系统显示"ADJUST"可调状态,此时旋钮调节光的亮度,即PWM波的占空比,如果此时按下"存储"键,则此时的亮度值被记录下来并保存,共可以记录下三个不同的亮度.

2.如你按下"模式"键,此时旋钮被屏蔽,只能调用你存储的三个亮度值,分别为"MODE 1","MODE 2","MODE 3"方便你的使用.

3.时间设置的两个按键可以实时调整时间.

二.程序(picc 8.05)

1.主程序

/***************************************************************
* 标题:PWM输出 *
* 作者:Wujieflash *
* 日期:2008年1月25日 *
* 功能:使用PIC的CCP模块输出PWM波 *
***************************************************************/
#include
#include "LCD1602_init.h"
#include "ds1302.h"
#include "i2c.h"

static volatile bitGODONE@ ((unsigned)&ADCON0*8)+2;
uch k,kb,kmem;
void PWMinit()
{
TRISC=0xfb;//设置C口状态
PORTC=0x00;
PR2=0xff; //设置PWM波的周期
CCP1CON=0x0c;
CCPR1L=0x1c;//设置占空比

T2CON=0x01; //设置1:4预分频
TMR2ON=1; //开启定时器2
}
/*-------------------------------------------------------*/

void AD_convert_init() //旋钮采样输出
{
uch i;
ADCON1=0x00;
ADCON0=0x01;
for(i=0;i<100;i++);
GODONE=1;
}
/*-------------------------------------------------------*/

void ADScan()
{

if(GODONE==0)
{
if(ADRESH>0xe3)ADRESH=0xe3; //限制占空比的范围
if(ADRESH<0x1c)ADRESH=0x1c;
CCPR1L=ADRESH;
GODONE=1;

}
}
/*-------------------------------------------------------*/

void KeyScan() //设置时间子程序
{
int d;

if(RC6==0) //设置键按下
{
k++; //选定入口值
k=k%3;
}
while(1)
{
if(RC6==1)break;//等待按键松开
}
switch(k)//键盘服务入口
{
case 1://设置分
{
d=R1302(0x83);//读取分
d=d/16*10+d%16;//转换为16进制
minute=flag; //设置秒的闪烁标志
hour=1; //其余变量不闪烁

if(minute==0) //闪烁
{
WriteCommand_1602(0xce);
WriteData_1602(0x00);
WriteData_1602(0x00);
}
if(RC7==0) //分数值加1
{
d++;
if(d>0x3b)d=0;//大于59就为0
d=d/10*16+d%10;
W1302(0x82,d);//写入DS1302
while(1)
{
if(RC7==1)break;//等待键松开
}
}
break;
}
case 2://设置时
{
d=R1302(0x85);//读取时
d=d/16*10+d%16;//转换为16进制
hour=flag; //设置秒的闪烁标志
minute=1; //其余变量不闪烁

if(hour==0) //闪烁
{
WriteCommand_1602(0xcb);
WriteData_1602(0x00);
WriteData_1602(0x00);
}
if(RC7==0) //时数值加1
{
d++;
if(d>0x17)d=0;//大于59就为0
d=d/10*16+d%10;
W1302(0x84,d);//写入DS1302
while(1)
{
if(RC7==1)break;//等待键松开
}
}
break;
}
case 0://设置完毕,不闪烁
{
minute=1;
hour=1;
break;
}
}
}
/*-------------------------------------------------------*/

void KeyScan1() //输出显示子程序
{
if(RC0==0) //模式键
{
kb++;
kb=kb%2;
}
while(1)
{
if(RC0==1)break;
}
switch(kb)
{
case 0: //可调模式,
{
ADON=1;//旋钮有效
WriteCommand_1602(0x80);
WriteData_1602('A');
WriteData_1602('D');
WriteData_1602('J');
WriteData_1602('U');
WriteData_1602('S');
WriteData_1602('T');
WriteCommand_1602(0x8a);
WriteData_1602(0x00);
WriteData_1602(0x00);
WriteData_1602(0x00);
WriteData_1602(0x00);
WriteData_1602(0x00);
WriteData_1602(0x00);

if(RC5==0) //存储键
{
kmem++;
kmem=kmem%3;
while(1)
{
if(RC5==1)break;
}
switch(kmem)
{
case 1:
{
w_24cl01b(0x00,ADRESH); //写入第一通道
WriteCommand_1602(0x8a);
WriteData_1602('C');
WriteData_1602('H');
WriteData_1602('1');
WriteData_1602(0x00);
WriteData_1602('O');
WriteData_1602('K');
break;
}
case 2:
{
w_24cl01b(0x01,ADRESH); //写入第二通道
WriteCommand_1602(0x8a);
WriteData_1602('C');
WriteData_1602('H');
WriteData_1602('2');
WriteData_1602(0x00);
WriteData_1602('O');
WriteData_1602('K');
break;
}
case 0:
{
w_24cl01b(0x02,ADRESH); //写入第三通道
WriteCommand_1602(0x8a);
WriteData_1602('C');
WriteData_1602('H');
WriteData_1602('3');
WriteData_1602(0x00);
WriteData_1602('O');
WriteData_1602('K');
break;
}
}
}
break;
}
case 1: //"MODE"模式
{
ADON=0; //屏蔽旋钮
WriteCommand_1602(0x80);
WriteData_1602('M');
WriteData_1602('O');
WriteData_1602('D');
WriteData_1602('E');
WriteData_1602(0x0);
WriteData_1602(0x0);

if(RC1==0) //模式一
{
CCPR1L=r_24cl01b(0x00);
ADRESH=r_24cl01b(0x00);
while(1)
{
if(RC1==1)break;
}
WriteCommand_1602(0x8a);
WriteData_1602('C');
WriteData_1602('H');
WriteData_1602('1');
WriteData_1602(0x00);
WriteData_1602(0x00);
WriteData_1602(0x00);
}
if(RC3==0) //模式二
{
CCPR1L=r_24cl01b(0x01);
ADRESH=r_24cl01b(0x01);
while(1)
{
if(RC3==1)break;
}
WriteCommand_1602(0x8a);
WriteData_1602('C');
WriteData_1602('H');
WriteData_1602('2');
WriteData_1602(0x00);
WriteData_1602(0x00);
WriteData_1602(0x00);
}
if(RC4==0) //模式三
{
CCPR1L=r_24cl01b(0x02);
ADRESH=r_24cl01b(0x02);
while(1)
{
if(RC4==1)break;
}
WriteCommand_1602(0x8a);
WriteData_1602('C');
WriteData_1602('H');
WriteData_1602('3');
WriteData_1602(0x00);
WriteData_1602(0x00);
WriteData_1602(0x00);
}
break;
}
}
}
/*-------------------------------------------------------*/

void DisplaySet(uch val) //显示占空比子程序
{
int pwm,pwm_shi,pwm_ge;
if(val>0xe3)val=0xe3;
if(val<0x1c)val=0x1c;
pwm=val*100/255;
pwm_shi=0x30+pwm/10;
pwm_ge=0x30+pwm%10;
WriteCommand_1602(0xc4);
WriteData_1602(pwm_shi);
WriteData_1602(pwm_ge);
WriteData_1602('%');
}
/*-------------------------------------------------------*/

void main()
{
init1602();
i2c_init();
AD_convert_init();
TMR1init();
PWMinit();
while(1)
{
ADScan();
DisplaySet(ADRESH);
FlashMaohao();
DisplayTime1602();
KeyScan();
KeyScan1();
}
}
2.I2C子程序

/***************************************************************
* 标题:I2C协议 *
* 作者:Wujieflash *
* 日期:2008年2月2日 *
* 功能:I2C通讯协议 *
***************************************************************/
#define nop() asm("nop")
#define SCL RD6
#define SDA RD7

void i2c_init()
{
TRISD6=0;
TRISD7=0;
RD6=0;
RD7=0;
}
/*------------------------------------------------------------------*/
//start
void start_iic()
{
SDA=1;
nop();
nop();
SCL=1;
nop();
nop();
nop();
nop();
SDA=0;
nop();
nop();
SCL=0;//it is ready to send data
nop();
}
/*------------------------------------------------------------------*/
//stop
void stop_iic(void)
{
SDA=0;
nop();
nop();
SCL=1;
nop();
nop();
nop();
nop();
SDA=1;
nop();
}
/*------------------------------------------------------------------*/
//send ack
void ack_iic()
{
SDA=0;
nop();
nop();
SCL=1;
nop();
nop();
nop();
nop();
SCL=0;
nop();
nop();
}
/*------------------------------------------------------------------*/
//send nack
void nack_iic()
{
SDA=1;
nop();
nop();
SCL=1;
nop();
nop();
nop();
nop();
SCL=0;
nop();
nop();
}
/*------------------------------------------------------------------*/
//send 1 byte
void send_iic(char c)
{
uch i;
for(i=0;i<8;i++)
{
SCL=0;
if((c<{
SDA=1;
}
else
{
SDA=0;
}
SCL=1;
nop();
nop();
nop();
nop();
SCL=0;
nop();
}
SDA=1;
TRISD7=1;
SCL=1;
nop();
nop();
nop();
nop();
SCL=0;
nop();
TRISD7=0;
}
/*------------------------------------------------------------------*/
//receive 1 byte
uch receive_iic(void)
{
uch rxbuf=0;
uch i;
//SDA=1;

TRISD7=1;
for(i=0;i<8;i++)
{
SCL=0;
nop();
nop();
nop();
nop();
nop();
SCL=1;
nop();
nop();
rxbuf=rxbuf<<1;
if(SDA==1)
{
rxbuf=rxbuf+1;
}
nop();
nop();
}

SCL=0;
nop();
TRISD7=0;
return(rxbuf);
}
/*------------------------------------------------------------------*/
//write 24cl01b subroutine
void w_24cl01b(unsigned char addr,unsigned char data)
{
int i;
start_iic();
send_iic(0xa0);
send_iic(addr);
send_iic(data);
stop_iic();
for(i=0;i<500;i++);
}
/*------------------------------------------------------------------*/
//read 24cl01b subroutine
char r_24cl01b(unsigned char addr)
{
int i;
uch data;
start_iic();
send_iic(0xa0);
send_iic(addr);

start_iic();
send_iic(0xa1);

data=receive_iic();
nack_iic();
stop_iic();
for(i=0;i<1000;i++);
return(data);
}

3.1602操作子程序

/***************************************************************
* 标题:LCD1602驱动 *
* 作者:Wujieflash *
* 日期:2008年1月29日 *
* 功能:驱动1602液晶的驱动程序 *
***************************************************************/
#include

#define RS RD0
#define RW RD1
#define E RD2

#define uch unsigned char

//延时子程序
void delay_1602(int time)
{
while(time--);
}
/*-----------------------------------------------*/

//写命令子程序
void WriteCommand_1602(uch command)
{
RS=0;
RW=0;

delay_1602(400);
E=1;
PORTB=command;
E=0;
}
/*-----------------------------------------------*/

//写数据子程序
void WriteData_1602(uch data)
{
RS=1;
RW=0;

delay_1602(400);
E=1;
PORTB=data;
E=0;
}
/*-----------------------------------------------*/

//初始化LCD1602子程序
void init1602()
{
TRISD0=0;
TRISD1=0;
TRISD2=0;
RD0=0;
RD1=0;
RD2=0;
TRISB=0;
PORTB=0;
WriteCommand_1602(0x01);
WriteCommand_1602(0x38);
WriteCommand_1602(0x0c);
WriteCommand_1602(0x80);
//WriteData_1602('M');
//WriteData_1602('O');
//WriteData_1602('D');
//WriteData_1602('E');
//WriteData_1602(':');
WriteCommand_1602(0xc0);
WriteData_1602('P');
WriteData_1602('W');
WriteData_1602('M');
WriteData_1602(':');
}
4.时钟子程序

/***************************************************************
* 标题:DS1302数字时钟 *
* 作者:Wujieflash *
* 日期:2008年1月29日 *
* 功能:显示日历与时间的程序 *
***************************************************************/
#define RST RD3
#define SCLK RD4
#define IO RD5
uch flag=0;
uch minute=1,hour=1;
uch clock[]={0};
uch DisCash[]={0x00,0x30,0x09,0x16,0x01,0x03,0x09};
/////往1302写入1Byte数据////////////////////////
void RTInputByte(uch d)
{
uch i;
TRISD3=0;
TRISD4=0;
TRISD5=0;
for(i=8; i>0; i--)
{
IO = d&0x01; //取最低位
SCLK = 1; //上升沿发送
SCLK = 0; //恢复
d = d >> 1;
}
}
///////从1302读取1Byte数据////////////////////////
uch RTOutputByte(void)
{
uch i,val=0;
TRISD5=1; //设置为输入
for(i=8; i>0; i--)
{
val = val >>1;
if(IO)val=val|0x80;// 从最低位开始接收
SCLK = 1; //下降沿接收
SCLK = 0;
}
TRISD5=0;
return(val);
}
///////先写地址,后写命令/数据//////////////////////////
void W1302(uch ucAddr, uch ucDa)
{
RST = 0;
SCLK = 0;
RST = 1; //打开DS1302
RTInputByte(ucAddr); // /* 地址,命令 */
RTInputByte(ucDa); // /* 写1Byte数据*/
SCLK = 1;
RST = 0; //关闭DS1302
}
///////先写地址,后读命令/数据////////////////////////
uch R1302(uch ucAddr)
{
uch ucData;
RST = 0;
SCLK = 0;
RST = 1;
RTInputByte(ucAddr); // /* 地址,命令 */
ucData = RTOutputByte(); // /* 读1Byte数据 */
SCLK = 1;
RST = 0;
return(ucData);
}
/////////向1302写入 秒 分 时 日 月 星期 年 */////////////
void Set1302(uch *pClock)
{
uch i;
uch ucAddr = 0x80; //起使地址
W1302(0x8e,0x00); ///* 控制命令,WP=0,允许写操作*/
for(i =7; i>0; i--)
{
W1302(ucAddr,*pClock); ///* 秒 分 时 日 月 星期 年 */
pClock++;
ucAddr +=2; //写地址加2
}
W1302(0x8e,0x80); // /* 控制命令,WP=1,写保护*/
}
////////从1302读出 秒 分 时 日 月 星期 年 *//////////////////
void v_Get1302(unsigned char ucCurtime[])
{
unsigned char i;
unsigned char ucAddr = 0x81;
for(i=0;i<7;i++)
{
ucCurtime[i] = R1302(ucAddr);///*格式为: 秒 分 时 日 月 星期 年 */
ucAddr += 2;
}
}

//使用LCD1602显示
void DisplayTime1602()
{
uch hour_shi,hour_ge,minute_shi,minute_ge;
v_Get1302(clock);
hour_shi=0x30+clock[2]/16;
hour_ge=0x30+clock[2]%16;
minute_shi=0x30+clock[1]/16;
minute_ge=0x30+clock[1]%16;

if(hour==1)
{WriteCommand_1602(0x80+0x4b);
WriteData_1602(hour_shi);
WriteData_1602(hour_ge);
}

if(minute==1)
{WriteCommand_1602(0x80+0x4e);
WriteData_1602(minute_shi);
WriteData_1602(minute_ge);
}
}
//TRM1初始化子程序
void TMR1init()
{
//TRM1 INITIAL
T1CON=0X30; //8分频
TMR1IF=0; //清中断标志
TMR1IE=1; //使能定时器1中断
TMR1L=0XDB; //初始值(定时0.5S)
TMR1H=0X0B;
TMR1ON=1; //开定时器1
}

//冒号闪烁子程序
void FlashMaohao()
{
if(TMR1IF==1)
{
TMR1ON=0;
TMR1IF=0;
TMR1L=0XDB; //重新付初值
TMR1H=0X0B;
flag++;
flag=flag%2; //闪烁标志在0-1间翻转
TMR1ON=1;
}
if(flag==0)
{
WriteCommand_1602(0xcd);
WriteData_1602(':');
}
if(flag==1)
{
WriteCommand_1602(0xcd);
WriteData_1602(0x00);
}
}

三.总结

虽然是完成了,但还有很多遗憾:

1.并没有完全仿真出来,主要由于软件需要的数字和模拟器件太多,资源太多,运行不过来.

2.有些实物已经验证的程序在PROTEUS上却失败,如24C01能写入,却读出来总为0,事实却可以的.

3.程序逻辑性还是差了点,感觉很混乱.

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

本文中,主要在于讲解如何利用pic单片机实现红外夜视仪设计。如果你对本文内容具有兴趣,不妨继续往下阅读哦。

关键字: pic单片机 指数 红外夜视仪

为帮助大家解决pic单片机应用难点,本文将对pic单片机硬件死锁问题予以讲解。

关键字: pic单片机 指数 死锁

电子相关专业的朋友对于pic单片机自然十分熟悉,为增进大家对pic单片机的认识,本文将继续为大家介绍pic单片机。本文中,小编将对pic单片机的PAGE和BANK予以阐述。

关键字: pic单片机 指数 单片机

对于pic单片机,大家都很熟悉,pic单片机是诸多类型单片机中最为受用的一款。本文是《pic单片机实际应用,基于pic单片机实现IC卡读写器(上)》的余下内容。如果你对pic单片机具有兴趣,抑或对pic单片机的应用充满好...

关键字: ic卡读写器 pic单片机 指数

为帮助大家增进对pic单片机的认识,本文将介绍如何基于pic单片机实现IC卡读写器。本文仅为上篇,剩余内容请翻阅下篇。

关键字: pic单片机 指数 ic卡读写器

为增进大家对pic单片机的了解,本文将对pic单片机开发环境以及pic单片机的引脚3状态予以讲解。如果你对pic单片机具有兴趣,不妨继续往下阅读哦。

关键字: pic单片机 开发环境 指数

  当人们晚上迷失在野外手上只有一个手电筒,此时有直升机飞过。人们用手电筒发出三短三长三短的光线。用这个国际通用的SOS求救信号,告诉飞行员来救你。人们规定的三短三长三短的光线,代表SOS就是一

关键字: pic单片机 通信协议

PIC单片机是一种用来开发和控制外围设备的集成电路(IC)。一种具有分散作用(多任务)功能的CPU。与人类相比,大脑就是CPU,PIC 共享的部分相当于人的神经系统,应用十分广泛,本文就为大家介

关键字: pic32 pic单片机

本文将基于两点对pic单片机予以阐述:1.如何挑选合适的pic单片机,2.pic单片机或运算符运用。如果你对本文内容具有一定兴趣,不妨继续往下阅读哦。

关键字: pic单片机 指数 或运算符

本文中,小编将介绍如何将pic单片机A/D转换数据打包,以达到减少空间、提高效率的目的。如果你对本文内容具有一定兴趣,不妨继续往下阅读哦。

关键字: pic单片机 指数 ad转换数据
关闭
关闭