第四章PIC16F877A功能及其编程

合集下载

PIC16F877A矩阵键盘的用法

PIC16F877A矩阵键盘的用法

PIC16F877A矩阵键盘的用法Post By:2010-9-27 13:39:00/*********************************************************************** ********Platform: PIC1687AProject : 实验16:矩阵式按键Clock F : 外部4MSoftware: PICCAuthor : 竹林清风comments:学习使用矩阵式按键的用法本例功能是按一下相应键,数码管显示相应的值0-9;不带连发,不带组合,希望有兴趣的人帮忙完成并共享UP键按键计数proteus仿真通过;************************************************************************ *******/#include <pic.h>#include <pic1687x.h>#include"delay.h"#include"key.h"unsigned char led_7[]={0x3f,0x06,0x5b,0x4F,0x66,0x6d,0x7d,0x07,0x7f,0x6f};//数码管显示值unsigned char key_temp;void main(void){unsigned char ID=0;TRISB=0X00;//所有B0端口输出PORTB=0XFF;TRISD=0X0F;//初始化键盘接口PORTD=0XFF;//置输出为高电平while(1){delay_nms(5);key_temp = read_keyboard(); // 调用键盘接口函数读键盘 if (key_temp != No_key){ // 有按键按下switch(key_temp){case 1:PORTB=led_7[1];break;case 2:PORTB=led_7[2];break;case 3:PORTB=led_7[3];break;case 4:PORTB=led_7[4];break;case 5:PORTB=led_7[5];break;case 6:PORTB=led_7[6];break;case 7:PORTB=led_7[7];break;case 8:PORTB=led_7[8];break;case 9:PORTB=led_7[9];break;case K3_2:PORTB=led_7[0];break;case 13:if(++ID>=10){ID=0;}PORTB=led_7[ID];break;}}}}下面为延时函数:文件delay.cvoid delay_1us(void) //1us {asm("nop");}void delay_nus(unsigned int n) //N us延时函数{unsigned int i=0;for (i=0;i<n;i++)delay_1us();}void delay_1ms(void) //1ms延时函数{unsigned int i;for (i=0;i<1140;i++);}void delay_nms(unsigned int n) //N ms延时函数{unsigned int i=0;for (i=0;i<n;i++)delay_1ms();}头文件:delay.hvoid delay_1us(void);void delay_nus(unsigned int n); //N us延时函数void delay_1ms(void); //1ms延时函数void delay_nms(unsigned int n); //N ms延时函数键盘key.h#define No_key 255#define K1_1 1#define K1_2 2#define K1_3 3#define k1_4 4#define K2_1 5#define K2_2 6#define K2_3 7#define K2_4 8#define K3_1 9#define K3_2 0#define K3_3 10#define K3_4 11#define K4_1 12#define K4_2 13#define K4_3 14#define K4_4 15#define Key_mask 0b00001111unsigned char read_keyboard(){static unsigned char key_state = 0, key_value, key_line;unsigned char key_return = No_key,i,key_time;switch (key_state){case 0:key_line = 0b00010000;for (i=1; i<=4; i++) // 扫描键盘{PORTD = ~key_line; // 输出行线电平PORTD = ~key_line; // 必须送2次!!!key_value = Key_mask & PORTD; // 读列电平if (key_value == Key_mask)key_line <<= 1; // 没有按键,继续扫描else{key_state++; // 有按键,停止扫描break; // 转消抖确认状态}}break;case 1:if (key_value == (Key_mask & PORTD)) // 再次读列电平, {switch (key_line | key_value) // 与状态0的相同,确认按键 { // 键盘编码,返回编码值case 0b00011110:key_return = K1_1; //"1"key_state++;break;case 0b00011101:key_return = K1_2; //"2"key_state++;break;case 0b00011011:key_return = K1_3; //"3"key_state++;break;case 0b00010111:key_return = k1_4; //"4" key_state++;break;case 0b00101110:key_return = K2_1; //"5" key_state++;break;case 0b00101101:key_return = K2_2; //"6" key_state++;break;case 0b00101011:key_return = K2_3; //"7" key_state++;break;case 0b00100111:key_return = K2_4; //"8" key_state++;break;case 0b01001110:key_return = K3_1; //"9" key_state++;break;case 0b01001101:key_return = K3_2; //"0" key_state++;break;case 0b01001011:key_return = K3_3; //"A"key_state++;break;case 0b01000111:key_return = K3_4; //"B"key_state++;break;case 0b10001110:key_return = K4_1; //"C"key_state++;break;case 0b10001101://key_return = K4_2; //"D"// key_state++;key_time=0;key_state=3;break;case 0b10001011:key_return = K4_3; //"E"key_state++;break;case 0b10000111:key_return = K4_4; //"F"key_state++;break;}// 转入等待按键释放状态}elsekey_state--; // 两次列电平不同返回状态0,(消抖处理)break;case 2: // 等待按键释放状态PORTD = 0b00000111; // 行线全部输出低电平 PORTD = 0b00000111; // 重复送一次if ( (Key_mask & PORTD) == Key_mask)key_state=0; // 列线全部为高电平返回状态0 break;case 3:PORTD = 0b00000111; // 行线全部输出低电平 PORTD = 0b00000111; // 重复送一次if ( (Key_mask & PORTD) == Key_mask){key_state=0; // 列线全部为高电平返回状态0 key_return = K4_2;}//break;else if( (Key_mask & PORTD)!=Key_mask) {if(++key_time>=100){key_state=4;key_time=0;key_return=20;}}break;case 4:PORTD = 0b00000111; // 行线全部输出低电平PORTD = 0b00000111; // 重复送一次if ( (Key_mask & PORTD) == Key_mask){key_state=0; // 列线全部为高电平返回状态0 //key_return = K4_2;}else if(++key_time>=20){key_time=0;key_return=20;}break;}return key_return;}此主题相关图片如下ju.jpg:。

PIC16F877A的特殊功能配置

PIC16F877A的特殊功能配置

PIC16F877A的特殊功能配置CPU的特殊功能BIT13CP:闪存程序存储器代码保护位0:所有程序存储器代码保护1:关闭代码保护BIT12Unimplemented:读时为结果为1BIT11DEBUG:在电路调试模式位0:在电路调试功能有效,RB6和RB7专用于调试器1:在电路调试功能失效,RB6和RB7用于本身的IO或其它功能BIT10-9WRT1-0:闪存程序存储器写使能位WRT1WRT0说明11写保护关闭,所有程序存储器由EECON控制写100000h到00ffh写保护;0100h到1fffh由EECON控制写010000h到07ffh写保护;0800h到1fffh由EECON控制写000000h到0fffh写保护;1000h到1fffh由EECON控制写BIT8CPD:数据EEPROM存储器代码保护位0:数据EEPROM存储器代码保护开启1:数据EEPROM存储器代码保护关闭BIT7LVP:低电压(单电源)的在线串行编程使能位0:RB3/PGM是普通IO口功能,编程时MCLR管脚必须是高电压1:RB3/PGM是PGM功能,低电压编程使能BIT6BOREN:欠压复位使能位0:欠压复位失效1:欠压复位使能BIT5-4Unimplemented:读时结果为1BIT3PWRTEN:上电延时定时器使能位0:上电延时定时器使能1:上电延时定时器失效BIT2WDTEN:看门狗定时器使能位0:看门狗失效1:看门狗使能BIT1-0:Fosc1:Fosc0:时钟源选择位Fosc1Fosc0时钟源11RC振荡器10外部石英高频晶振HS【频率范围见下表】01外部石英晶振XT【频率范围见下表】00外部低频石英晶振LP【频率范围见下表】。

PIC16F877A功能及其编程

PIC16F877A功能及其编程
RA3=1; NOP(); RA4=0;
4.1.1 端口A
因此,在使用RA口时,除了要设置TRISA外,有 时相关寄存器也要设置。
注意:在上电复位时,与AN有关的端口的默认 设置是作为模拟端口,即ADCON1(见4.6)中默认 值为0b00xx0000,这个值的设置结果是除RA4外的所 有的RA引脚都作为模拟输入。
信的时钟线; RC7/RX/DT:IO引脚、异步串行通信的接收、同步串行通
信的数据线。
4.1.4 端口D
端口D有8个引脚,它除了作为普通IO口外, 还能作为并行从动口使用。
4.1.5 端口E 端口E只有3个引脚,它们都可以作为AD转换
的模拟电压输入口,功能如下:
RE0/RD/AN5:IO引脚、并行从动口的读控制、 模拟电压输入通道AN5;
➢ 中断的特点:可返回性。中断处理结束后必须能 回到原先的程序,并且能继续运行原先的程序,
这就需要在中断时能进行现场保护与恢复。
中断的执行过程
➢ 中断发生:程序执行到某行,突然事件(能够产 生中断的事件)发生,产生中断。
➢ 断点保护:CPU自动将中断时刻即将要执行的下 一条指令的地址压入堆栈。
➢ 中断响应:CPU自动将PC强制设为0X0004,且GIE =0。执行中断服务程序(自动完成现场保护与恢 复,手动清中断标志位)。
将被调试系统占用,因此在调试时此二个引脚暂 不能使用。
3、8个引脚具有内部弱上拉使能控制 由OPTION_REG寄存器的第7位RBPU控制,如果弱 上拉使能,作为输入的RB口在端口悬空时将被上拉 到高电平。以RB0为例,如下图所示:
4、RB0/INT具有外部中断功能。
5、RB的的高4位还具有电平变化中断功能
ADIE

pic16f877a编程实例

pic16f877a编程实例

pic16f877a编程实例pic16f877a是一款常用的单片机,被广泛应用于嵌入式系统中。

它具有多种功能和强大的性能,可以实现各种应用需求。

本文将以pic16f877a编程实例为主题,介绍其基本特性和常见应用。

pic16f877a是一款8位单片机,采用哈佛架构,具有高性能和低功耗的特点。

它内置了8KB的程序存储器,368字节的数据存储器,以及35个I/O引脚,可以满足大多数嵌入式系统的需求。

我们来看一个简单的实例,通过pic16f877a控制LED灯的开关。

```c#include <pic16f877a.h>void main() {TRISB0 = 0; // 设置RB0为输出引脚while(1) {RB0 = 1; // 将RB0引脚电平设置为高,LED灯亮__delay_ms(1000); // 延时1秒RB0 = 0; // 将RB0引脚电平设置为低,LED灯灭__delay_ms(1000); // 延时1秒}}```在上面的程序中,我们首先将RB0引脚设置为输出引脚,然后进入一个无限循环。

在循环中,我们将RB0引脚电平设置为高,LED灯亮起,然后延时1秒;然后将RB0引脚电平设置为低,LED灯熄灭,再次延时1秒。

通过不断重复这个过程,我们可以实现LED灯的闪烁效果。

除了控制LED灯,pic16f877a还可以用来控制其他外设,如蜂鸣器、液晶显示屏等。

下面是一个使用pic16f877a控制蜂鸣器的实例。

```c#include <pic16f877a.h>void main() {TRISB0 = 0; // 设置RB0为输出引脚while(1) {RB0 = 1; // 将RB0引脚电平设置为高,蜂鸣器鸣叫__delay_ms(1000); // 延时1秒RB0 = 0; // 将RB0引脚电平设置为低,蜂鸣器停止鸣叫__delay_ms(1000); // 延时1秒}}```在上面的程序中,我们同样将RB0引脚设置为输出引脚,并进入一个无限循环。

PIC16F877A控制诺基亚5110简单程序(稍微修改即可用到其他单片机)

PIC16F877A控制诺基亚5110简单程序(稍微修改即可用到其他单片机)

#include <pic.h>__CONFIG(0x3B31);#define uchar unsigned char#define uint unsigned intconst char Hzk[4][16]={//秦{0x20,0x22,0x2A,0xAA,0x6A,0x2A,0x3A,0x2F,0xAA,0xAA,0x6A,0xAA,0x2A,0x22,0x20,0x00},{0x02,0x42,0x41,0x24,0x15,0x0D,0x05,0xFF,0x04,0x0C,0x14,0x24,0x41,0x02,0x02,0x00},//鲁{0x10,0x08,0xFC,0xAA,0xAB,0xAA,0xAA,0xFA,0xAA,0xAA,0xAE,0xA8,0xF8,0x00,0x00,0x00},{0x02,0x02,0x02,0xFA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xFA,0x02,0x02,0x02,0x00},};#define LCD_DC RE0#define LCD_SDIN RE1#define LCD_SCLK RE2#define LCD_SCE RB1#define LCD_RST RB2void delay(uint ms){uint i,j;for(j=0;j<ms;j++)for(i=0;i<11;i++);}void init(){ADCON1 = 0x87; //设置PORTE为普通IO口TRISD = 0x00; //设置PORTD为输出TRISE = 0x00; //设置PORTE为输出TRISB=0x00;}void send_com(uchar Data){uchar a;LCD_SCE=0;LCD_DC=0;for(a=0;a<8;a++){if(Data&0x80)LCD_SDIN=1;elseLCD_SDIN=0;LCD_SCLK=0;LCD_SCLK=1;Data=Data<<1;}LCD_SCE=1;}void send_data(uchar Data){uchar a;//定义局域变量一定要放在子函数的最前LCD_SCE=0;LCD_DC=1;for(a=0;a<8;a++){if(Data&0x80)LCD_SDIN=1;elseLCD_SDIN=0;LCD_SCLK=0;LCD_SCLK=1;Data=Data<<1;}LCD_SCE=1;}void LCD_init(){LCD_RST = 0; // 产生一个让LCD复位的低电平脉冲delay(10);LCD_RST = 1;send_com(0x21); // 使用扩展命令设置LCD模式send_com(0xc8); // 设置液晶偏置电压send_com(0x06); // 温度校正send_com(0x13); // 1:48send_com(0x20); // 使用基本命令,V=0,水平寻址// LCD_clear(); // 清屏send_com(0x0c); // 设定显示模式,正常显示LCD_SCE = 0; // 使能LCD}void LCD_POS(uchar X,uchar Y){if(X<=83 && Y<=5){send_com(0x40|Y);send_com(0x80|X);}}void LCD_clear(void){unsigned char t;unsigned char k;LCD_POS(0,0);for(t=0;t<6;t++){for(k=0;k<84;k++){send_data(0x00);}}}void display(){uchar x,y;for(y=0;y<2;y++){LCD_POS(0,y);for(x=0;x<16;x++)send_data(Hzk[y][x]);}for(y=2;y<4;y++){LCD_POS(16,y-2);for(x=0;x<16;x++)send_data(Hzk[y][x]);}}void main(){init();LCD_init();LCD_clear();while(1){display();}}。

pic16f单片机例程

pic16f单片机例程

pic16f单片机例程如何在PIC16F单片机上实现一个简单的LED闪烁程序PIC16F系列是微芯科技公司推出的8位单片机系列产品,被广泛应用于各种嵌入式系统中。

其中,PIC16F877A是该系列中应用最广泛的一款单片机。

本篇文章将介绍如何使用PIC16F877A单片机,通过编写一个简单的LED闪烁程序来展示其基本的程序控制能力。

第一步:准备硬件设备要实现LED闪烁程序,我们需要以下硬件设备:- PIC16F877A 单片机- 开发板- LED- 适配器(用于将单片机上的数字电压转换为LED所需的电压)将PIC16F877A单片机插入开发板的合适位置上,并连接好适配器和LED。

确保硬件设备连接正确,以便在编写程序后能够顺利进行实验和调试。

第二步:编写闪烁程序C语言是编写PIC单片机程序的常用语言。

我们将使用MPLAB X IDE和XC8编译器来编写闪烁程序。

按照以下步骤进行设置和编写程序。

1. 安装MPLAB X IDE以及XC8编译器,确保其正常运行。

2. 打开MPLAB X IDE,创建一个新工程。

选择"Microchip Embedded" -> "Standalone Project",并选择合适的工具链(例如:XC8)。

3. 选择PIC16F877A作为目标设备。

4. 定义单片机的时钟频率和相关配置参数。

在项目窗口的“Properties”下,选择"XC8 Global Options" -> "PIC14/PIC16" -> "Configuration bits",并设置好需要的参数(例如:时钟频率、使能位等)。

5. 在工程目录下创建一个新的.c文件,用于编写闪烁程序。

例如:ledBlink.c6. 编写闪烁程序的代码。

以下是一个简单的LED闪烁程序示例:c#include <xc.h>#define _XTAL_FREQ 8000000函数声明void init(void);void delay(void);主函数int main(void) {init();无限循环while(1) {设置LED端口为高电平PORTDbits.RD0 = 1;延时delay();设置LED端口为低电平PORTDbits.RD0 = 0;延时delay();}return 0;}void init(void) {将RD0引脚配置为输出TRISDbits.RD0 = 0;初始化RD0引脚为低电平PORTDbits.RD0 = 0;}void delay(void) {延时函数,用于控制LED闪烁的速度__delay_ms(500);}第三步:编译和下载程序完成程序的编写后,我们需要将其编译成二进制文件并下载到PIC16F877A单片机中。

PIC16F877A单片机AD数模转换

PIC16F877A单片机AD数模转换

在ADON=1的前提下: 0: A/D转换已经完成(自动清零) 或表示未进行A/D转换; 1: 启动A/D转换过程或表明A/D转换 正在进行.
第四章A/D转换 4.2.2 PIC16F877片内ADC模块简介 2. ADC控制寄存器ADCON1
பைடு நூலகம்ADFM PCFG3 PCFG 2 PCFG1 PCFG0
第四章A/D转换
B7 ADCS1 B6 ADCS0 B5 CHS2 B4 CHS1 B3 CHS0 B2 GO/ DONE B1 B0 ADON
00:选择系统时钟,频率为fosc/2; 01:选择系统时钟,频率为fosc/8; 10:选择系统时钟,频率为fosc/32; 11:选择内部阻容(RC)振荡器,频率 为fR C
第四章A/D转换
4.3 编程方法及实例
CLRF PORTC ; 对C口清0 AtoD NOP ;为了保证采样时间,通常,应该插入20靤以上的 NOP ;时间延迟或者安排一段有相当长度的应用程序. BSF ADCON0,GO ;GO位置1,开始A/D转换 ADWAIT: BTFSC ADCON0,GO ;在A/D转换完成后,GO位将被清0 GOTO ADWAIT ;如果没有转换完毕,则返回继续检测 MOVF ADRESH,W;如果转换完毕,把A/D结果读入W中 MOVWF PORTC ;将AD结果写入C口 GOTO AtoD ;循环进行A/D转换 END
第四章A/D转换
4.2 A/D转换器的主要技术指标和PIC16F877片内ADC模 块简介
3
转换精度
A/D转换器的转换精度定义为一个实际A/D转换器在量化值上的 差值.可用绝对误差或相对误差表示.
第四章A/D转换 4.2 A/D转换器的主要技术指标和PIC16F877片内 ADC模块简介 4.2.2 PIC16F877片内ADC模块简介 PIC16F877内部嵌入的ADC模块是10位数字量 精度,共有8个模拟信道.与ADC模块有关的寄 存器比较多,共有11个 1.A/D控制寄存器

pic16f877a程序

pic16f877a程序

实验二程序清单:(1)编写程序使8个LED实现双跳灯显示//===========led程序===========#include <pic.h>//===========变量定义==========void delay(int z);//===========主程序============main(){TRISD=0x00;while(1){PORTD=0x03;delay(200);PORTD=0x0c;delay(200);PORTD=0x30;delay(200);PORTD=0xc0;delay(200);}}void delay(int z){int x,y;for(x=z;x>0;x--)for(y=120;y>0;y--);}(2)编写程序实现8个LED灯高四位和低四位交替点亮//===========led程序===========#include <pic.h>//===========变量定义==========void delay(int z);//===========主程序============main(){TRISD=0x00;while(1){PORTD=0xf0;delay(500);PORTD=0x0f;delay(500);}}void delay(int z){int x,y;for(x=z;x>0;x--)for(y=120;y>0;y--);}(3)编写程序使第一次按下按键时单双星闪(1、3、5、7个 LED灯与2、4、6、8个LED交替点亮),第二次按下按钮时高四位的LED和低四位的LED交替点亮,这两种显示方式依次循环#include <pic.h>//===========变量定义==========void delay(int z);void KEYSCAN();#define shuru RB0unsigned int i,j;//===========主程序============ main(){TRISD=0x00;TRISB=0X01;//设置RB0为输入i=0;PORTD=0XFF;while(1){KEYSCAN();if(i%2==1){PORTD=0xaa;delay(500);PORTD=0x55;delay(500);}if(i%2==0){PORTD=0xf0;delay(500);PORTD=0x0f;delay(500);}}}void delay(int z){int x,y;for(x=z;x>0;x--)for(y=120;y>0;y--);}void KEYSCAN(){while(1){if(shuru==1)break;} /*等待有键按下*/delay(10); /*软件延时*/if(shuru==1)i++; /* 如果仍有键按下,则调用键服务子程序*/}实验三程序清单:(1)4*4键盘扫描#include<pic.h> //包含单片机内部资源预定义const charLEDCODE[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7c,0x 39,0x5e,0x79,0x71};int result;void delay(); //delay函数申明void init(); //I/O口初始化函数申明void scan(); //按键扫描程序申明void display(int x); //显示函数申明//---------------------------------------------------//主程序void main(){while(1) //循环工作{init(); //调用初始化子程序scan(); //调用按键扫描子程序display(result); //调用结果显示子程序}}//---------------------------------------------------//初始化函数void init(){TRISD=0X0f; //设置C口高4位为输入,低4位为输出TRISC=0X00; //设置D口为输出PORTC=0X00;PORTD=0X00; //先清除所有显示}//按键扫描程序void scan(){PORTD=0XEF; //C3输出低电平,其他三位输出高电平asm("nop"); //插入一定延时,确保电平稳定result=PORTD; //读回C口高4位结果result=result&0x0f; //清除低4位if(result!=0x0f) //判断高4位是否为全1(全1代表没按键按下)?{result=result|0xE0; //否,加上低4位0x07,做为按键扫描的结果return;}PORTD=0XDF; //C3输出低电平,其他三位输出高电平asm("nop"); //插入一定延时,确保电平稳定result=PORTD; //读回C口高4位结果result=result&0x0f; //清除低4位if(result!=0x0f) //判断高4位是否为全1(全1代表没按键按下)?{result=result|0xD0; //否,加上低4位0x07,做为按键扫描的结果return;}PORTD=0XBF; //C3输出低电平,其他三位输出高电平asm("nop"); //插入一定延时,确保电平稳定result=PORTD; //读回C口高4位结果result=result&0x0f; //清除低4位if(result!=0x0f) //判断高4位是否为全1(全1代表没按键按下)?{result=result|0xB0; //否,加上低4位0x07,做为按键扫描的结果return;}PORTD=0X7F; //C3输出低电平,其他三位输出高电平asm("nop"); //插入一定延时,确保电平稳定result=PORTD; //读回C口高4位结果result=result&0x0f; //清除低4位if(result!=0x0f) //判断高4位是否为全1(全1代表没按键按下)?{result=result|0x70; //否,加上低4位0x07,做为按键扫描的结果return;}}//显示程序void display(int x){switch(result){case 0xee:PORTC= LEDCODE[0];delay();break; case 0xed:PORTC= LEDCODE[1];delay();break; case 0xeb:PORTC= LEDCODE[2];delay();break; case 0xe7:PORTC= LEDCODE[3];delay();break;case 0xde:PORTC= LEDCODE[4];delay();break;case 0xdd:PORTC= LEDCODE[5];delay();break; case 0xdb:PORTC= LEDCODE[6];delay();break; case 0xd7:PORTC= LEDCODE[7];delay();break;case 0xBE:PORTC= LEDCODE[8];delay();break;case 0xbd:PORTC= LEDCODE[9];delay();break; case 0xBb:PORTC= LEDCODE[10];delay();break; case 0xb7:PORTC= LEDCODE[11];delay();break; case 0x7E:PORTC= LEDCODE[12];delay();break; case 0x7d:PORTC= LEDCODE[13];delay();break; case 0x7b:PORTC= LEDCODE[14];delay();break;case 0x77:PORTC= LEDCODE[15];delay();break;}}//延时程序void delay() //延时程序{int i; //定义整形变量for(i=0x100;i--;); //延时}(2)数码管显示#include<pic.h> //包含单片机内部资源预定义// __CONFIG(0x1832);//芯片配置字,看门狗关,上电延时开,掉电检测关,低压编程关,加密,4M晶体HS振荡void delay(); //delay函数申明void init(); //I/O口初始化函数申明char TABLE[]={0,1,2,3,4}; //定义常数0-5的数据表格const charLEDCODE1[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x00};//共阴码void main(){init(); //调用初始化函数while(1) //死循环,让数码管持续{PORTC=0X01; //点亮第1位数码管PORTD=~LEDCODE1[TABLE[0]]; //D口输出数据表格第1个数据0 delay();PORTD=0xFF; //延时一定时间,保证数码管亮度PORTC= 0x02;PORTD=~LEDCODE1[TABLE[1]]; //显示数据1delay();PORTD=0xFF;PORTC= 0x04;PORTD=~LEDCODE1[TABLE[2]]; //显示数据2delay();PORTD=0xFF;PORTC= 0x08;PORTD=~LEDCODE1[TABLE[3]]; //显示数据3delay();PORTD=0xFF;}}void init() //I/O口初始化函数{TRISC=0X00; //设置A0输出,其他输入TRISD=0X00; //设置D口输出PORTC=0x00;PORTD=0x00; //先熄灭所有显示}void delay() //延时程序{int i; //定义整形变量for(i=0xF000;i--;); //延时 //0x400for(i=0xff;i--;);}void display(){int i ;unsigned char DISPBIT;DISPBIT=0x01;for (i=0;i<=3;i++){PORTC=DISPBIT; //点亮第1位数码管PORTD=~LEDCODE1[TABLE[i]]; //D口输出数据表格第1个数据0 delay();PORTD=0xFF;DISPBIT=DISPBIT<<1;}}实验四程序清单:(1)方波发生器#include<pic.h>sbit P1_0=P1^0;void timer0(void){P1_0=!P1_0;TH0=-(1000/256); /*计数初值重装*/TL0=-(1000%256);}void main(void){TMOD=0x01; /*T0工作在定时器方式1*/P1_0=0;TH0=-(1000/256); /*预置计数初值*/TL0=-(1000%256);EA=1; /*CPU开中断*/ET0=1; /*T0开中断*/TR0=1; /*启动T0*/do{}while(1);}(2)程序说明:P1口输出,低电平有效#include<pic.h>#define uchar unsigned char //定义无符号字符#define uint unsigned int //定义无符号整数void Delayms(uint x){ //定义延时函数uint i,j;for(i=x;i>0;i--)for(j=110;j>0;j--);}void main(){uint i;uchar temp;while(1){temp=0x01; //8个流水灯逐个闪动for(i=0;i<8;i++){P1=~temp;Delayms(300);temp<<=1;}temp=0x80; //8个流水灯反向逐个闪动for(i=0;i<8;i++){P1=~temp;Delayms(300);temp>>=1;}temp=0xfe; //8个流水灯依次全部点亮for(i=0;i<8;i++){P1=temp;Delayms(300);temp<<=1;}temp=0x7f; //8个流水灯依次反向全部点亮for(i=0;i<8;i++){P1=temp;Delayms(300);temp>>=1;}}}实验六程序清单:(1) U1发送部分程序清单#include<pic.h>unsigned tran[10]={0,2,4,6,8,1,3,5,7,9};unsigned char k,x;int i=0;const chartable[20]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xD8,0x80,0x90,0x88,0x83,0x c6,0xa1,0x86,0x8c,0x7f,0xbf,0x89,0xff};void sciint(){SPBRG=0x19;TXSTA=0x04;RCSTA=0x80;TRISC6=1;TRISC7=1;TRISB=0x00;}void delay(){for(i=0x1FFF;i>0;i--) {;}}void display(){for(k=0;k<10;k++) { x=tran[k];PORTB=table[x];delay();}}main(){sciint();di();TXEN=1;CREN=1;for(k=0;k<10;k++){ TXREG=k;while(1){if(TXIF==1)break;}while(1){if(RCIF==1)break;}RCREG=RCREG;}display();while(1){;}}(2) U2接收部分程序清单#include<pic.h>unsigned rece[10];unsigned char k,x;int i=0;const chartable[20]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xD8,0x80,0x90,0x88,0x83,0x c6,0xa1,0x86,0x8c,0x7f,0xbf,0x89,0xff};void sciint(){SPBRG=0x19;TXSTA=0x04;RCSTA=0x80;TRISC6=1;TRISC7=1;TRISB=0x00;}void delay(){for(i=0x1FFF;i>0;i--){;}}void display(){for(k=0;k<10;k++) { x=rece[k];PORTB=table[x]; delay();}}main(){sciint();di();CREN=1;TXEN=1;for(k=0;k<10;k++){ while(1){if(RCIF==1)break;}rece[k]=RCREG; TXREG=rece[k];while(1){if(TXIF==1)break;}}display();while(1){;}}实验七程序清单:(1)单路显示#include<pic.h>unsigned int i;unsigned int a,b,c;static inttable[20]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xD8,0x80,0x90,0x88,0x83,0x c6,0xa1,0x86,0x8c,0x7f,0xbf,0x89,0xff};void initial() //初始化{TRISB=0x00; //定义为输出PORTB=0x13; //数码管全灭TRISC=0x00;PORTC=0x13;a=0;b=0;c=0;}void ADC() //A/D转换初始化{ADCON0=0x41; //0100 0001 选择转换时钟8Tosc,选择A/D通道为RA0,//打开A/D转换器。

PIC16F877A万年历程序

PIC16F877A万年历程序

PIC16F877A万年历程序时间:2009-03-05 来源: 作者:Wujieflash 点击:1639 字体大小:【大中小】为了把KS0108系列的液晶吃透,特别制作了这款万年历,感觉效果还是不错的.希望大家分享我的喜悦,毕竟有了更多志同道合的朋友支持,我才能更进一步提高.一,原理介绍说明:1.单片机还是采用PIC中最经典的PIC16F877A,端口多,功能全,特别是他有8K的ROM,这是我选择的主要原因,因为储存液晶的字库需要很大的空间.2.液晶显示还是用的KS0108系列,主要是他性价比高,指令简单,特别是公司也在用.3.时钟/日历芯片用的DALLOS的DS1302芯片,他可以储存从2000-2099年的日历,及实时时钟,可以方便的读写.4.温度测量还是用的DS18B20,这在我上一实例中已经用过,有兴趣可以查阅.5.本万年历可以显示实时时钟,精确到秒,年,月,日,星期,阴历,温度,生肖等,显示的信息量大. 6,可以通过按键自由设定时钟及日历,按"设置"键可以在秒,分,时,日,月,星期,年之间来回切换,要设置的单元以闪烁提醒.通过"+"."-"按键可以把要设置的单元设定到预想状态.二,程序说明:本程序有许多小的模块,现分列如下:1.主程序/**************************************************** 标题:万年历** 作者:Wujieflash ** 日期:2008年1月13日** 说明:包含文件***************************************************/ #include#include "ziku.h"#include "lcd_init.h"#include "ds1302.h"#include "ds18b20.h"#include "keyscan.h"#include "yinli.h"//子程序//LCD显示空白边框子程序void LCDShowTable(){uch i;SlectScreen(1); //写左半屏SetLine(0); //起使页SetColumn(0); //起使列for(i=0;i//显示固定字符子程序void LCDShowGudingWord(){Show8X16_2(0,24,s0);Show8X16_2(0,32,s0);Show8X16(2,1,s0);Show8X16(2,9,s0);Show16X16_3(6,40,ri);Show16X32(2,24,ss0);Show16X32(2,40,ss0);Show8X16_2(0,64,s0);Show8X16_2(0,72,s0);Show8X16_2(0,80,maohao);Show8X16_2(0,88,s0);Show8X16_2(0,96,s0);Show8X16_2(0,104,maohao);Show8X16_2(0,112,s0);Show8X16_2(0,119,s0);Show8X16(2,80,s0);Show8X16(2,88,s0);Show16X16_2(4,64,shiyi);Show16X16_2(4,80,yue);Show16X16_2(4,95,chu);Show16X16_2(4,111,yi);Show16X16_3(6,72,sheng);Show16X16_3(6,88,xiao);Show16X16_3(6,104,shu);Show16X16_2(0,40,nian);Show16X16(4,2,yue);Show16X16_3(6,8,xing);Show16X16_3(6,24,qi);Show16X16(2,96,danwei1);Show8X16_2(0,8,s2);Show8X16_2(0,16,s0);}/*----------------------------------------------------------*/ //TRM1初始化子程序void TMR1init(){//TRM1 INITIALT1CON=0X30; //8分频TMR1IF=0; //清中断标志TMR1IE=1; //使能定时器1中断TMR1L=0XDB; //初始值(定时0.5S)TMR1H=0X0B;TMR1ON=1; //开定时器1}//冒号闪烁子程序void FlashMaohao(){static uch timecount=0;if(TMR1IF==1){TMR1ON=0;TMR1IF=0;TMR1L=0XDB; //重新付初值TMR1H=0X0B;flag++;flag=flag%2; //闪烁标志在0-1间翻转TMR1ON=1;timecount++;if(timecount==120)//1分钟采样一次温度{timecount=0;get_temp(); //温度转换子程序}}if(flag==0){Show8X16_2(0,80,maohao);Show8X16_2(0,104,maohao);}if(flag==1){Show8X16_2(0,80,noshu);//清除Show8X16_2(0,104,noshu);}}//主程序void main(){TMR1init(); //定时器1初始化keyinit(); //键盘初始化LCDinit(); //LCD操作初始化LCDShowTable(); //显示空白表格LCDShowGudingWord(); //显示固定字符//Set1302(DisCash); //设置初始时间(默认写入我写程序的时间) get_temp(); //读取温度while(1){v_Get1302(clock); //读取时间、日历display();YangToYin(clock[6]/16*10+clock[6]&0x0f,clock[4]/16*10+clock[4]&0x0f,clock[3]/16*1 0+clock[3]&0x0f);FlashMaohao(); //冒号闪烁KeyScan(); //键盘扫描}}2.测温程序:/**************************************************** 标题:DS18B20测温** 作者:Wujieflash ** 日期:2008年1月13日** 说明:使用DS18B20芯片测温****************************************************/# define DQ RC3 //定义18B20数据端口# define DQ_DIR TRISC3 //定义18B20D口方向寄存器# define DQ_HIGH() DQ_DIR =1 //设置数据口为输入# define DQ_LOW() DQ = 0; DQ_DIR = 0 //设置数据口为输出unsigned char TLV=0 ; //采集到的温度高8位unsigned char THV=0; //采集到的温度低8位unsigned char TZ=0; //转换后的温度值整数部分//------------------------------------------------//延时函数//系统初始化函数void init(){ADCON1=0X07; //设置A口为普通数字口TRISA=0X00; //设置A口方向为输出//TRISC3=0; //设置D口方向为输出}//-----------------------------------------------//复位DS18B20函数reset(void){char presence=1;while(presence){DQ_LOW() ; //主机拉至低电平delay(2,90); //延时503usDQ_HIGH(); //释放总线等电阻拉高总线,并保持15~60us delay(2,8); //延时70usif(DQ==1) presence=1; //没有接收到应答信号,继续复位else presence=0; //接收到应答信号delay(2,70); //延时430us}}//-----------------------------------------------//写18b20写字节函数void write_byte(uch val){uch i;uch temp;for(i=8;i>0;i--){temp=val&0x01; //最低位移出DQ_LOW();NOP();NOP();NOP();NOP();NOP(); //从高拉至低电平,产生写时间隙if(temp==1) DQ_HIGH(); //如果写1,拉高电平delay(2,7); //延时63usDQ_HIGH();NOP();NOP();val=val>>1; //右移一位}}//------------------------------------------------//18b20读字节函数uch read_byte(void){uch i;uch value=0; //读出温度static bit j;for(i=8;i>0;i--){value>>=1;DQ_LOW();NOP();NOP();NOP();NOP(); //6usDQ_HIGH(); //拉至高电平NOP();NOP();NOP(); //4usj=DQ;if(j) value|=0x80;delay(2,7); //63us}return(value);}//-------------------------------------------------//启动温度转换函数void get_temp(){int i;DQ_HIGH();reset(); //复位等待从机应答write_byte(0XCC); //忽略ROM匹配write_byte(0X44); //发送温度转化命令for(i=10;i>0;i--){delay(201,132); //调用多次延迟函数,确保温度转换完成所需要的时间}reset(); //再次复位,等待从机应答write_byte(0XCC); //忽略ROM匹配write_byte(0XBE); //发送读温度命令TLV=read_byte(); //读出温度低8THV=read_byte(); //读出温度高8位DQ_HIGH(); //释放总线TZ=(TLV>>4)|(THV<<4);}3.日历显示程序/*************************************************** * 标题:DS1302读写** 作者:Wujieflash ** 日期:2008年1月14日** 说明:日历显示范围:2000年--2099年****************************************************/ #define RST RC0#define SCLK RC1#define IO RC2uch flag=0;uch second=1,minute=1,hour=1,year=1,month=1,date=1,day=1; uch clock[]={0};uch DisCash[]={0x00,0x30,0x09,0x16,0x01,0x03,0x09};/////往1302写入1Byte数据////////////////////////void RTInputByte(uch d){uch i;TRISC=0x00;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;TRISC2=1; //设置为输入for(i=8; i>0; i--){val = val >>1;if(IO)val=val|0x80;// 从最低位开始接收SCLK = 1; //下降沿接收SCLK = 0;}return(val);}///////先写地址,后写命令/数据////////////////////////// void W1302(uch ucAddr, uch ucDa){RST = 0;SCLK = 0;RST = 1; //打开DS1302RTInputByte(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/////////与LCD的显示接口//////////////////////void display(){uch i;for(i=0;i4.按键扫描与服务程序/*************************************************** * 标题:按键扫描和服务** 作者:Wujieflash ** 日期:2008年1月17日** 说明:当按键按下,选中的单元就会闪烁****************************************************/ uch k=0;//键盘初始化子程序void keyinit(){TRISD0=1;TRISD0=1;TRISD0=1;}/*----------------------------------------------------------*/ //键盘扫描子程序void KeyScan(){int d;if(RD0==0) //设置键按下{k++; //选定入口值k=k%8;}while(1){if(RD0==1)break;//等待按键松开}switch(k)//键盘服务入口{case 1://设置秒{d=R1302(0x81);//读取秒d=d/16*10+d%16;//转换为16进制second=flag; //设置秒的闪烁标志minute=1; //其余变量不闪烁hour=1;year=1;month=1;date=1;day=1;if(second==0) //闪烁{Show8X16_2(0,111,noshu);Show8X16_2(0,119,noshu);}if(RD1==0) //秒数值加1{d++;if(d>0x3b)d=0;//大于59就为0 d=d/10*16+d%10;W1302(0x80,d);//写入DS1302 while(1){if(RD1==1)break;//等待键松开}}if(RD2==0)//数值减1{d--;if(d0x3b)d=0;d=d/10*16+d%10;W1302(0x82,d);while(1){if(RD1==1)break;}}if(RD2==0){d--;if(d0x17)d=0;d=d/10*16+d%10;W1302(0x84,d);while(1){if(RD1==1)break;}}if(RD2==0){d--;if(d0x1f)d=1;d=d/10*16+d%10;W1302(0x86,d); while(1){if(RD1==1)break; }}if(RD2==0){d--;if(d0x0c)d=1;d=d/10*16+d%10; W1302(0x88,d); while(1){if(RD1==1)break; }}if(RD2==0){d--;if(d0x07)d=1;d=d/10*16+d%10; W1302(0x8a,d); while(1){if(RD1==1)break; }}if(RD2==0){d--;if(d0x63)d=0;d=d/10*16+d%10; W1302(0x8c,d); while(1){if(RD1==1)break;}}if(RD2==0){……5.液晶显示程序/**************************************************** 标题:LCD操作** 作者:Wujieflash ** 日期:2008年1月12日** 说明:KS0108系列液晶不带字库****************************************************/#include#define E RA0 //液晶使能端#define RW RA1 //读写控制端#define DI RA2 //数据/指令通道#define CSA RA5 //片选#define CSB RA3 //片选#define nop() asm("nop")////////////////////////基本子函数/////////////////////////延时void delay(char x,char y){char z;do{z=y;do{;}while(--z);}while(--x);}//其指令时间为:7+(3*(Y-1)+7)*(X-1)如果再加上函数调用的call 指令、页面设定、传递参数花掉的7 个指令。

PIC16F877ASPI通信C程序

PIC16F877ASPI通信C程序
char number;//存放PORTD的数,全局变量
void main(void)
{
CSH();//初始化
number=0x0D;
while(1)
{
if(b==1)//若按键,则进行读写操作
{
WRITE(number);//发送数据
//RB5=1;
DELAY(1);
ERROR=0;//错误标志位清零
PORTD=0;
SSPEN=1;//相应的引脚为一般的I/O口
CKP=1;//空闲时钟为高电平
SMP=1;//在数据信号的末端采样
CKE=1;//下降沿发送数据
SSPCON+=0b0001;//主控模式,时钟为fosc/16
}
char SPI_WRITE(char R )
{char BUF;
SSPBUF=R;//要发的数写入SSPBUF寄存器
{
for (k=1024;k>0;k--)NOP();//DELAY(30);//防抖动
INTF=0;//清标志位
b=1;
}
}
//延时(n)ms
void DELAY(unsigned int n)
{unsigned int j;
char k;
for (j=0;j<n;j++)
for (k=246;k>0;k--)NOP();
char SPI_WRITE(char R); //SPI发送函数
void WRITE(char number);//SPI写函数
void READ(void);//SPI接收函数
void interrupt ISR(void);//按键中断程序

PIC16F877A例程---DS18B20

PIC16F877A例程---DS18B20

#include <pic.h>#include <pic1687x.h>__CONFIG(0x3F32); //芯片配置字#define LCDRS RB2#define LCDRW RB1#define LCDE RB0#define LCDDA TA PORTD#define DS18B20 RE0#define TRIS_B20 TRISE0void LCD1602_INIT(void);void WRITE_LCD_CMD (char cmd);void WRITE_LCD_DA TA (char data);void LCD_Display(char *s);void LCD_Display_location (char line, char col);void LCD1602_BUSY();void US_delay ( int t);void itoa10(unsigned char *buf, int i);int strlen (const char *s);void DS18B20_INIT();void WRITE_DS18B20_CMD(char cmd);float READ_DS18B20 ();char bank1 DA T_BUFF1[]= "Temperature:";char Found_DS18B20[]="DS1820 FOUND";char DS18B20_NOT_Found[]="DS1820 NOT FOUND"; char bank1 DA T_BUFF2[]= " ";#define CLRLCD 0X01 //清屏命令#define LCDMOD 0X38 //8位,两行,5*7点#define TURNON 0X0F //#define CURMODE 0X06 //#define ORG1 0X80 //LCD 第一行首地址#define ORG2 0XC0 //LCD 第二行首地址#define SKIPROM 0XCC#define READSCRACHPAD 0XBE#define TCONVERT 0X44#define DS18b20_RESET 10#define DSRECOVER 1float temperature;char bank1 atemperature[10]; // used for store ascii code of digital temperature */void main(){int len;ADCON1=0X07;LCD1602_INIT();LCD_Display(DA T_BUFF1);LCDE=0;LCD_Display_location (1,0);while (1){DS18B20_INIT();WRITE_DS18B20_CMD(SKIPROM);WRITE_DS18B20_CMD(TCONVERT);TRIS_B20=0;DS18B20=0;TRIS_B20=1;while(1){ //判断转换是否完成if (DS18B20) break;else continue;}DS18B20_INIT();WRITE_DS18B20_CMD(SKIPROM);WRITE_DS18B20_CMD(READSCRACHPAD);temperature=READ_DS18B20();itoa10(atemperature, (int) (temperature * 10));// so use temperature * 10 to enlarge the temperature len=strlen(atemperature);atemperature[len]=atemperature[len-1];atemperature[len-1]='.';atemperature[len+1]=0;LCD_Display_location (0,0);LCD_Display (DA T_BUFF1); //LCD第一行显示Tempereture: 字符LCD_Display_location (1,0);LCD_Display (DA T_BUFF2);LCD_Display_location (1,2);LCD_Display (atemperature); //LCD第二行显示当前温度值LCD_Display (DA T_BUFF2);US_delay(5000); //每隔0.5秒读取一次温度值}}int strlen(const char * s){const char *cp;cp = s;while(*cp++)continue;return cp-s-1;}void LCD_Display(char *s){int len;int atmp;len=strlen(s);for (atmp=0; atmp<len; atmp++)WRITE_LCD_DA TA(s[atmp]);}void LCD1602_BUSY(){// char tmpbusy;TRISB &= 0xF8;TRISD=0XFF;LCDRS=0;LCDRW=1;LCDE=1;while(LCDDA TA & 0X80);}void LCD_Display_location (char line, char col){char pos;LCD1602_BUSY();pos = line * 0X40 + 0X80 + col;WRITE_LCD_CMD(pos);}void WRITE_LCD_DA TA(char data) {LCD1602_BUSY();TRISB & =0XF8;TRISD=0;LCDDA TA=data;LCDRS=1;LCDRW=0;LCDE=0;asm("NOP");asm("NOP");LCDE=1;}void WRITE_LCD_CMD(char cmd) {LCD1602_BUSY();TRISB & =0XF8;TRISD=0;LCDDA TA=cmd;LCDRS=0;LCDRW=0;LCDE=0;asm("NOP");asm("NOP");LCDE=1;}void LCD1602_INIT(void){LCD1602_BUSY();TRISB &= 0XF8;TRISD=0;WRITE_LCD_CMD(CLRLCD);WRITE_LCD_CMD(LCDMOD);WRITE_LCD_CMD(TURNON);WRITE_LCD_CMD(CURMODE);LCD_Display_location (0,0);}void DS18B20_INIT(){TRIS_B20=0;DS18B20=0;US_delay(20);TRIS_B20=1;US_delay(10);}void WRITE_DS18B20_CMD(char cmd) {char tmp;char i;TRIS_B20=0;for(tmp=8;tmp>0;tmp--){TRIS_B20=0;DS18B20= 0;asm ("NOP");asm ("NOP");asm ("NOP");asm ("NOP");asm ("NOP");if (cmd & 0x01){TRIS_B20=1;US_delay(1);for (i=5;i>0;i--);}else{DS18B20=0 ;US_delay(1);for (i=5;i>0;i--);TRIS_B20=1;}cmd=cmd/2;}}float READ_DS18B20 (){char tmp=0x01;float t;union{char c[2];int x;}temp;temp.x=0;while (tmp){ // read first 8 bitsTRIS_B20=0;DS18B20=0;asm("NOP");TRIS_B20=1;if (DS18B20)temp.c[0] |= tmp;tmp=tmp<<1;US_delay(2);}tmp=1;while (tmp){ // read first 8 bitsTRIS_B20=0;DS18B20=0;asm("NOP");TRIS_B20=1; // release the busasm("NOP");if (DS18B20) // "1" presentedtemp.c[1] |= tmp;tmp=tmp<<1;US_delay(2);}t=((float) temp.x)/16.0 ;return t;}void itoa10(unsigned char *buf, int i){unsigned int rem;unsigned char *s,length=0;s = buf;if (i == 0)*s++ = '0';else{if (i < 0){*buf++ = '-';s = buf;i = -i;}while (i){++length;rem = i % 10;*s++ = rem + '0';i /= 10;}for(rem=0; ((unsigned char)rem)<length/2; rem++){*(buf+length) = *(buf+((unsigned char)rem));*(buf+((unsigned char)rem)) = *(buf+(length-((unsigned char)rem)-1));*(buf+(length-((unsigned char)rem)-1)) = *(buf+length);}}*s=0;}void US_delay( int i){unsigned char j;while(i--){j=3;while(j--);}}。

lcd1602_pic16f877a_程序_代码

lcd1602_pic16f877a_程序_代码
{
uint i;
uchar j;
for(i=0;i<2;i++)
{
j&=0x00;
j|=(dat&0xf0);
PORT=j;
PORT&=0x0f;//清高四位
PORT|=(dat&0xf0);//写高四位
if(x==1)
RS=1;
else
RS=0;
delay(3);
EN=1;
delay(3);
EN=0;
lcd_write(0x01,0);//显示清零,数据指针d location(uint x,uint y)
{
if(x==1)
{
lcd_write(0x80+y,0);
}
if(x==2)
{
lcd_write(0xc0+y,0);
}
}
void lcd_prins(uint x,uint y,uint z)//这里不能用uchar z,否则当z=6578,即四位或五位数时,放不下而导致出错
//lcd_single_prins(uint x,uint y,uint z);
////
//2013,01,07 //
/***********************************************/
#define uchar unsigned char
#define uint unsigned int
void delay(uint x);
void lcd_write(uchar dat,uchar x);
//延时函数
void delay(uint x)
{

PIC16F877A数字时钟时钟程序

PIC16F877A数字时钟时钟程序

;Digit clock;-----------------------------------------------;DA TE :20101205;Author:Tang HS;M C U :PIC16F877A;FileName : ClockPIC.ASM;-----------------------------------------------------------;Date: {2010/12/07.14:35}-V er01--CS-ICD:0xAFCE---ISP:0xb7ce----;功能: 1.LED显示:时分秒;格式:[ hh mm ss ] 备注:按键未定义;------------------------------------------------------------;-----------------------------------------------------------;Date: {2010/12/07.22:15}-V er01--CS-ICD:0xAFCE---ISP:0xb7ce----;功能: 1.LED显示:时分秒;格式:[ hh mm ss ] 备注:按键未定义; 2.RB0-SET_KEY;RB1-ADD_KEY;RB2-SUB_KEY;RB3-EXIT_KEY;------------------------------------------------------------;Date: {2010/12/09.18:06}-V er02--CS-ICD:0xAFCE---ISP:0xef0e----;************************************************************;Date: {2010/12/10.00:47}-V er03--CS-ICD:0xb08d---ISP:0xfaa7----;功能: 1.LED显示:时分秒;格式:[ hh mm ss ] 备注:按键未定义; 2.RB0-SET_KEY;RB1-ADD_KEY;RB2-SUB_KEY;RB3-EXIT_KEY 都OK ; 3.MOVLW 纠正MOVV REG,1 引起的SUB_不良;;--------------------------------------------------------------;Date: {2010/12/10.13:10}-V er03.1--CS-ICD:0xb08b---ISP:0xfaa4----; 4.时差。

AD模数转换_PIC16F877A

AD模数转换_PIC16F877A

从打开A/D通道或选择新的A/D通道到A/D转换器的内部保持电容充电至与输入的模拟电压相同的时间就是A/D采集时间,通常为20us左右,然后才能启动A/D转换。

在执行程序连续交替进行两路模拟输入信号的A/D转换时,GO位被置1后启动一次A/D 转换,只要等待一个T AD的时间,之后就可以修改CHS2:CHS0选择另外的输入信号通道而不会影响当前A/D转换的结果。

10位的A/D转换时间共需要12个T AD,T AD为一位的转换时间,对于887A来说,T AD最小为1.6us。

A/D转换过程如下:1、有关的I/O口设置为输入(TRISA或TRISE)2、对模拟引脚/基准电压/数字I/O进行设置,选择A/D结果格式(ADCON1)3、选择A/D通道,选择A/D时钟,A/D模块使能4、延时约20us,使得输入电压对保持电容充电达到稳定5、开始A/D转换(ADGO=1)6、A/D转换结束,ADGO自动清零,软件对PIR1的ADIF清零7、读A/D转换结果(ADRESH、ADRESL)如下程序://A/D转换,对指定通道k进行A/D转换,结果以16位整数返回//只进行AD通道等设置,ADCON1不在此设置unsigned int_AD_SUB( char k){char i;unsigned int x;ADCON0=0b 0100 0001; // T AD=8ToscADCON0 |=(k<<3); // 设置A/D转换通道,打开通道for (i=1;i<5;i++) NOP( ); // 打开AD通道后延时20us左右ADGO=1; // 开始A/D转换while(ADGO= =1); // 等待A/D转换结束ADIF=0; // 清A/D转换结束标志x=0;x=ADRESH<<8;x|=ADRESL;return( x);}PIC16F877A对模拟输入电压和参考电压的要求:(10/12位的AD转换)一个完整的A/D转换可以按如下步骤实现:1、设定ADCON1和TRISx寄存器,配置引脚的工作模式2、若需要中断响应,则要设定相关的中断控制寄存器3、设置ADCON0寄存器,选择A/D转换的时钟,选择模拟信号的输入通道,打开A/D模块,注意此时GO/DONE位不要置14、等待足够长的采样延时5、将ADCON0中的GO/DONE控制位置1,启动一次A/D转换过程6、查询A/D转换结束标志:GO/DONE位在A/D转换结束时会自动清0,ADIF标志位在A/D转换结束后会自动置1,这两个位都可以作为软件查询A/D转换是否结束的标志,使用ADIF标志时记得要用软件将其清除7、若使用中断来响应A/D转换的结束,则6将不再适用,A/D转换结束时ADIF的置位将使单片机进入中断服务程序,在处理中断时记得将ADIF标志位清08、A/D转换结束,直接从ADRES寄存器中读取8位转换结果,存入其缓冲单元或直接进行运算处理9、修改ADCON0寄存器的CHS2:CHS0,选择其他通道输入的模拟信号进行A/D转换,程序重复4—9的循环输入电压信号:为了防止电压输入而造成芯片损坏或出现硬件死锁的问题,一般要在输入信号电路中串接一个限流电阻后在接到单片机引脚上。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
unsigned int j; char k; for (j=0;j<n;j++)
for (k=246;k>0;k--) NOP();
}
以后此程序略,可参见附录:公用子程序。
返回目录
4.3 定时/计数器TMR0 TMR0是个8位计数/定时器
自带可编程预分频器,可对外部脉冲计数或对内部 指令脉冲计数(1:1~1:256)
这就需要在中断时能进行现场保护与恢复。
中断的执行过程
➢ 中断发生:程序执行到某行,突然事件(能够产 生中断的事件)发生,产生中断。
➢ 断点保护:CPU自动将中断时刻即将要执行的下 一条指令的地址压入堆栈。
➢ 中断响应:CPU自动将PC强制设为0X0004,且GIE =0。执行中断服务程序(自动完成现场保护与恢 复,手动清中断标志位)。
RA3=1; NOP(); RA4=0;
4.1.1 端口A
因此,在使用RA口时,除了要设置TRISA外,有 时相关寄存器也要设置。
注意:在上电复位时,与AN有关的端口的默认 设置是作为模拟端口,即ADCON1(见4.6)中默认 值为0b00xx0000,这个值的设置结果是除RA4外的所 有的RA引脚都作为模拟输入。
➢ 一条写IO引脚的指令如RB3=1,实际上是在指令的 开头读入整个B端口,并在指令周期的末尾时刻把 1写入RB端口3的输出锁存器。 如果立即对同一端口操作,如x=PORTB,在指令 周期的开始处,由于前一指令产生在IO口的电平 尚未稳定,读入的可能是引脚的前一个状态而不 是新状态值。
因此连续对同一端口的操作时,最好用一个NOP 指令或者其他不访问该I/O 端口的指令隔开。
RD 并行口
中断 标志
AD转换 中断
标志
串行通 信接收
中断
标志
串行通 信发送
中断
标志
同步串 行通信
中断
标志
CCP1 模块 中断 标志
TMR2 溢出 中断 标志
TMR1 溢出 中断 标志
第二外围中断控制寄存器 PIE2:
bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0
- CMIE - EEIE BLCIE -
信的时钟线; RC7/RX/DT:IO引脚、异步串行通信的接收、同步串行通
信的数据线。
4.1.4 端口D
端口D有8个引脚,它除了作为普通IO口外, 还能作为并行从动口使用。
4.1.5 端口E 端口E只有3个引脚,它们都可以作为AD转换
的模拟电压输入口,功能如下:
RE0/RD/AN5:IO引脚、并行从动口的读控制、 模拟电压输入通道AN5;
TMR0溢 出中断
使能
外部触 发中断
使能
RB口的 高4位 电平变 化中断 使能
TMR0溢 出中断
标志
外部触 发中断
标志
RB口的 高4位 电平变 化中断 标志
第一外围中断控制寄存器 PIE1:
bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0
PSPIE ADIE RCIE TXTE SSPIE CCP1IE TMR2IE TMR1IE
RD 并行口
中断 使能
AD转换 中断
使能
串行通 信接收
中断
使能
串行通 信发送
中断
使能
同步串 行通信
中断
使能
CCP1 模块 中断 使能
TMR2 溢出 中断 使能
TMR1 溢出 中断 使能
第一外围中断标志寄存器 PIR1:
bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0
PSPIF ADIF RCIF TXTF SSPIF CCP1IF TMR2IF TMR1IF
RE1/WR/AN6:IO引脚、并行从动口的写控制、 模拟电压输入通道AN6;
RE2/CS/AN7:IO引脚、并行从动口的片选控制、 模拟电压输入通道AN7。
返回目录
4.2 中断
➢ 中断的概念:正常程序运行时发生了事先设定的 事件,需要暂停原来运行的程序而转到处理目前 需要马上处理的事件。
➢ 中断的特点:可返回性。中断处理结束后必须能 回到原先的程序,并且能继续运行原先的程序,
与中断直接相关的位为INTEDG,它涉及到外 部中断(RB0/INT)的中断边沿选择,0为下降沿。
OPTION_REG=0b10111111; //等效 INTEDG=0
注意: ➢ 进入中断后硬件自动屏蔽全局中断,即中断后GIE=0,
中断返回后自动恢复全局中断允许,GIE=1。
➢ 因此,PIC16单片机不允许中断嵌套!也就是说,在 中断服务程序未退出时,即使有新的中断发生,也不 能进入中断。等当前的中断处理完成退出中断后才能 重新进入中断。
- 比较器 - EEPROM I2C

中断
写完成 总线冲
使能
中断 突中断
使能 使能
- CCP2IE

CCP2
模块
中断
使能
第二外围中断标志寄存器 PIR2:
bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0
- CMIF - EEIF BLCIF -
- 比较器 - EEPROM I2C
➢ 所有的I/O端口,上电复位默认值均为1,即为输 入口。
➢ 每个IO引脚的最大输出电流(拉电流)为20mA, 最大输入电流(灌电流)为25mA。
➢ 端口A、B、E的最大输入电流总和与输出电流总和 均为200mA;
➢ 端口C、D的最大输入电流总和与输出电流总和也 为200mA。
➢ 对I/O 端口的写操作是一个读-修改-写的过程。
当RB4~RB7引脚做为输入时,只要有一个引脚 的逻辑电平发生变化,就会使RB电平中断标志位 置1。这些功能的设置,与OPTION、INTCON有关, 参见相关各章节。
4.1.3 端口C
RC0/T1OSO/T1CKI:IO引脚、TMR1振荡输出、TMR1外部 脉冲输入;
RC1/T1OSI/CCP2:IO引脚、TMR1振荡输入、CCP2; RC2/CCP1:IO引脚、CCP1; RC3/SCK/SCL:IO引脚、SPI的时钟线、I2C的时钟线; RC4/SDI/SDA:IO引脚、SPI的数据输入、I2C的数据线; RC5/SDO:IO引脚、SPI的数据输出; RC6/TX/CK:IO引脚、异步串行通信的发送、同步串行通
每按一次按键,LED翻转亮
//例 用RB0/INT按键,每按一下,LED翻转亮 #include <pic.h>
__CONFIG(0x3F39); #define LED RB7 char A=0; //全局变量,保存LED状态
void DELAY(unsigned int); void interrupt ISR(void);
工作原理:递加计数。即由计数初值开始,每来若 干个计数脉冲(和预分频比有关),计数值+1,直 到255。若再加1,溢出,同时使计数当前值等于0
TMR0有溢出中断功能,T0IF将自动置1
若要对外部脉冲计数,必须 ①编程OPTION_REG ,(<T0CS>)置1 ②编程TRISA , RA4/T0CKI引脚设置为输入 ③硬件电路:符合一定要求的外部脉冲送RA4/T0CKI
中断控制寄存器:INTCON 相应使能位为1,允许中断;为0,禁止中断。 相应标志位为1,表示有中断发生,必须用软件清0。
bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0
GIE PEIE T0IE INTE RBIE T0IF INTF RBIF
全局中 断使能
外围中 断使能
}
//========中断服务程序 void interrupt ISR(void) { if (INTF==1)
{ DELAY(30); INTF=0; LED=!LED;
} }
//延时30ms,躲过抖动时间 //清中断标志位,须在延时之后!
//======延时(n)ms,4MHz晶振下 void DELAY(unsigned int n) {
第四章
PIC16F877A 功能及其编程
制作:王骞
2015.9
4.1 输入输出端口
4.2 中断
4.3 定时/计数器TMR0
4.4 定时/计数器TMR1
4.5 定时/计数器TMR2
4.6 A/D转换器
4.7 CCP模块(Capture/Compare/PWM)
4.8 异步串行通信(USART)
4.9 EEPROM的读写
ADIE
RCIF ×
RCIE
TXIF ×
TXIE
BCLIF ×
BCLIE
PSPIF ×
PSPIE
GIE控制所只有有的在中SL断E源EP状 态下能运行的模块
PEIE控制了12个中断源 产生中断才能唤醒 SLEEP。
与门:只有所有的输入为1,输出才为1 或门:只要有一个输入为1,输出就为1
中断逻辑示意图
void main(void)
{ OPTION_REG=0b00000000; //RB0为下降沿触发中断
TRISB =0b00000001; //设定RB0为输入,RB7为输出
INTCON=0b10010000; //允许RB0/INT中断
LED=0;
//初始状态LED灭
while(1);
//原地等待
×
× CCP1IF ×
CCP1IE
CCP2IF ×
CCP2IE
TMR1IF ×
TMR1IE
TMR2IF ×
TMR2IE
PSPIF ×
PSPIE
相关文档
最新文档