PIC16F887 实战编程 单片机编程 基础实验教程

article/2025/10/24 11:13:13

文章目录

  • 2 PIC工程建立与仿真
  • 3 单片机基础寄存器操作:
    • 3.1 IO
    • 3.2 模拟输入电压读取
    • 3.3 外部中断
    • 3.4 定时器中断
    • 3.5 串口UART
    • 3.6 IIC通信
  • 4 实际项目
  • 5 如何阅读代码
  • 6 如何把代码放到MPLAB V5.0+xc8 v2.0上工作?
    • 6.1 短暂的回顾
    • 6.2 xc8 v2.0程序结构
    • 6.3 移植操作指南
  • 7 常用的代码解释
    • 7.1 关于LCD1602
    • 7.2 memset清空 sprintf装填
  • 1 参考书籍:

基础操作需要看一下以下的博客,跟着走一遍。
安装MPLAB V4.05+XC8 V1.41,老师不会管你用什么版本,别的版本bug多,老版本反而好用:
https://blog.csdn.net/x1131230123/article/details/100907773
安装proteus 8.9:
https://blog.csdn.net/x1131230123/article/details/106951776
做一个基础实验(想改写到MPLAB V5+XC8 V2也看这里的博客6.3 移植操作指南):
https://blog.csdn.net/x1131230123/article/details/108757436

实物连接指南(持续更新):
https://blog.csdn.net/x1131230123/article/details/108780168

2 PIC工程建立与仿真

这一步主要教大家怎么做一个完整的工程,整个过程熟悉后,就可以做自己的实际项目了。
注意:下面你将阅读到的内容并不涉及到MPLAB和PROTEUS联合调试,先忘记你之前所学的然后跟着下面博客的去理解这个思路。
1、
首先去桌面创建2个文件夹,如下面这图。一个必须是英文的,一个可以中文;一个用于存放PIC工程的,一个存放proteus仿真文件。题外话:电脑用户名是中文的建议重装电脑系统。
在这里插入图片描述
2、
打开IDE
在这里插入图片描述
打开后:
在这里插入图片描述

3、
新建一个工程:
file->new project
在这里插入图片描述
嵌入式标准工程:
在这里插入图片描述
芯片型号
在这里插入图片描述
仿真器
在这里插入图片描述
npasm其实就是MPLAB自带的编译器,需要写汇编语言的。
下面的XC8是我们自己装的编译器产品,我们选XC8。注意!V1.41可以更好的编译,新的V2版本有的地方有bug,我不清楚指令的详细区别,所以直接建议就安装MPLAB V4.05 +XC8 V1.41 。
在这里插入图片描述
工程名字也必须英文,不然有bug:
在这里插入图片描述
选工程路径,去选择桌面上新建的那个文件夹,这样整个程序工程都会存在那个文件夹里。
在这里插入图片描述
编码选择UTF-8。什么是编码?
汉字编码有哪些? UTF-8才是最常用的编码,GB2312只是汉字编码太局限了。
在这里插入图片描述

完成后:
在这里插入图片描述
4、
为新建的工程添加一个main.c:右键点source files --> 左键点new --> 左键点main.c…
在这里插入图片描述
不要中文
在这里插入图片描述
这样就完成了!
在这里插入图片描述
5、
这个时候就可以编写单片机C程序了,写个简单的(下面这程序就是控制端口B的低四位输出0101电平):


#include <xc.h>// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.
// CONFIG1
#pragma config FOSC = XT        // Oscillator Selection bits (XT oscillator: Crystal/resonator on RA6/OSC2/CLKOUT and RA7/OSC1/CLKIN)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled and can be enabled by SWDTEN bit of the WDTCON register)
#pragma config PWRTE = OFF      // Power-up Timer Enable bit (PWRT disabled)
#pragma config MCLRE =ON      // RE3/MCLR pin function select bit (RE3/MCLR pin function is digital input, MCLR internally tied to VDD)
#pragma config CP = OFF         // Code Protection bit (Program memory code protection is disabled)
#pragma config CPD = OFF        // Data Code Protection bit (Data memory code protection is disabled)
#pragma config BOREN = OFF      // Brown Out Reset Selection bits (BOR disabled)
#pragma config IESO = OFF       // Internal External Switchover bit (Internal/External Switchover mode is disabled)
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor Enabled bit (Fail-Safe Clock Monitor is disabled)
#pragma config LVP = OFF        // Low Voltage Programming Enable bit (RB3 pin has digital I/O, HV on MCLR must be used for programming)// CONFIG2
#pragma config BOR4V = BOR40V   // Brown-out Reset Selection bit (Brown-out Reset set to 4.0V)
#pragma config WRT = OFF        // Flash Program Memory Self Write Enable bits (Write protection off)void main(void)
{TRISB=0b11110000;//高四位输入 低四位输出PORTB=0b00000101;//高四位的设置无效 低四位输出0101while(1){}
}

在这里插入图片描述

在所有的预处理指令中,#pragma
指令可能是最复杂的了,它的作用是设定编译器的状态或者是指示编译器完成一些特定的动作。#pragma指令对每个编译器给出了一个方法,在保持与C和C++语言完全兼容的情况下,给出主机或操作系统专有的特征。依据定义,编译指示是机器或操作系统专有的,且对于每个编译器都是不同的。

不用管前面那些#pragma,那些全是对xc8编译器进行一些设置的,告诉编译器怎么处理怎么处理。

6、
写好程序后,怎么把程序弄到单片机里?单片机需要的是hex文件。
我们是C语言是人看的,我们需要需要借助MPLAB和XC8将C语言编译成hex文件。
点击下图里的图标就可以将C语言编译好。

注意:这里是编译,英文单词是build,编译的目的是将c语言转换成hex机器文件,单片机只需要这个文件就能够正确执行我们的程序。
你如果需要联调、调试、运行这几个关键词,英文单词是debug或者run等字眼,这类操作只在看程序运行到哪里,运行成了什么情况,是嵌入式程序员在开发过程中所需要的一种模式(要是经验足够也不需要这种模式)。这种事情要么需要proteus联调设置,要么需要实物单片机连接仿真器后插入了你的电脑,不要去点这些,除非你在自己进行联调操作或者调试实物操作。
在这里插入图片描述
会在底下看到编译提示:

make -f nbproject/Makefile-default.mk SUBPROJECTS= .build-conf
make[1]: Entering directory 'C:/Users/xd_du/Desktop/PICproject/helloworld.X'
make  -f nbproject/Makefile-default.mk dist/default/production/helloworld.X.production.hex
make[2]: Entering directory 'C:/Users/xd_du/Desktop/PICproject/helloworld.X'
"D:\Program Files (x86)\Microchip\xc8\v1.41\bin\xc8.exe" --pass1  --chip=16F887 -Q -G  --double=24 --float=24 --opt=+asm,+asmfile,-speed,+space,-debug,-local --addrqual=ignore --mode=free -P -N255 --warn=-3 --asmlist -DXPRJ_default=default  --summary=default,-psect,-class,+mem,-hex,-file --output=default,-inhx032 --runtime=default,+clear,+init,-keep,-no_startup,-osccal,-resetbits,-download,-stackcall,+clib   --output=-mcof,+elf:multilocs --stack=compiled:auto:auto "--errformat=%f:%l: error: (%n) %s" "--warnformat=%f:%l: warning: (%n) %s" "--msgformat=%f:%l: advisory: (%n) %s"    -obuild/default/production/main.p1  main.c 
"D:\Program Files (x86)\Microchip\xc8\v1.41\bin\xc8.exe"  --chip=16F887 -G -mdist/default/production/helloworld.X.production.map  --double=24 --float=24 --opt=+asm,+asmfile,-speed,+space,-debug,-local --addrqual=ignore --mode=free -P -N255 --warn=-3 --asmlist -DXPRJ_default=default  --summary=default,-psect,-class,+mem,-hex,-file --output=default,-inhx032 --runtime=default,+clear,+init,-keep,-no_startup,-osccal,-resetbits,-download,-stackcall,+clib --output=-mcof,+elf:multilocs --stack=compiled:auto:auto "--errformat=%f:%l: error: (%n) %s" "--warnformat=%f:%l: warning: (%n) %s" "--msgformat=%f:%l: advisory: (%n) %s"      --memorysummary dist/default/production/memoryfile.xml -odist/default/production/helloworld.X.production.elf  build/default/production/main.p1     
Microchip MPLAB XC8 C Compiler (Free Mode) V1.41
Build date: Jan 24 2017
Part Support Version: 1.41
Copyright (C) 2017 Microchip Technology Inc.
License type: Node Configuration:: warning: (1273) Omniscient Code Generation not available in Free modeMemory Summary:Program space        used     Dh (    13) of  2000h words   (  0.2%)Data space           used     2h (     2) of   170h bytes   (  0.5%)EEPROM space         used     0h (     0) of   100h bytes   (  0.0%)Data stack space     used     0h (     0) of    60h bytes   (  0.0%)Configuration bits   used     2h (     2) of     2h words   (100.0%)ID Location space    used     0h (     0) of     4h bytes   (  0.0%)You have compiled in FREE mode.
Using Omniscient Code Generation that is available in PRO mode,
you could have produced up to 60% smaller and 400% faster code.
See http://www.microchip.com/MPLABXCcompilers for more information.make[2]: Leaving directory 'C:/Users/xd_du/Desktop/PICproject/helloworld.X'
make[1]: Leaving directory 'C:/Users/xd_du/Desktop/PICproject/helloworld.X'BUILD SUCCESSFUL (total time: 1s)
Loading code from C:/Users/xd_du/Desktop/PICproject/helloworld.X/dist/default/production/helloworld.X.production.hex...
Loading completed

我们的hex文件在哪里?编译完成后,我们就可以在桌面那个工程文件夹里去找下图里这个hex文件,这个文件就是机器文件。proteus加载这个文件就可以执行我们写的程序。!!!!找到这个文件我们就已经成功了!
在这里插入图片描述
题外话:编译的时候提示了一句话:

You have compiled in FREE mode.

题外话:所以如何才能不处于免费模式?右键工程–>properties–>按图里的点击。
题外话:作用:此选项选择编译器的基本操作模式。可用类型有pro、std和free。在PRO模式下运行的编译器使用完全优化并生成最小的代码大小。标准模式使用有限的优化,而自由模式只使用最小的优化级别,将生成相对较大的代码。
提示:选择PRO在很多时候都不是一个明智的选择,PRO模式在编译器会“智能地”改变一些C语言的汇编实现方法,这有时候会有益于代码的最优化,但有时候会显得有些“智障”,会让能你认为能好好工作的C代码工作起来不正常。这个PRO主要是提供给有经验的嵌入式开发工程师用于优化代码的。
在这里插入图片描述

7、
MPLAB中的事情已经进行完了,现在你已经知道怎么使用MPLAB建立工程,如何编写程序和编译程序,编译后的hex文件目录在哪里。
其实写好程序后,就可以链接仿真器进行下载(烧写)程序了。链接仿真器后,下面的run图标或者debug图标点一下,MPLAB都会自动讲hex文件烧写到实物单片机中,单片机就能够运行起来。这一步的操作是在调试实物的时候所用到的,字眼是debug。这里只是顺便提及一下,跟我们想要进行的仿真没有丝毫联系。
在这里插入图片描述

现在可以谈谈另一件事情,如何proteus仿真?
Proteus软件里面含有很多单片机和外部器件,能够模拟实物电路的运行。如果我们在Proteus软件里连接好需要的实物器件,然后将写好的程序(hex文件)加载到Proteus软件里的单片机器件里,那在Proteus软件中我们就可以看到整个电路的工作情况。我们的关注点就放到了Proteus软件中的器件连接中了。

8、
Proteus软件的安装和基础使用参见这个链接:
https://blog.csdn.net/x1131230123/article/details/106951776
新建仿真图–>添加器件PIC16F887
在这里插入图片描述
将hex文件加载到Proteus软件里的单片机器件里:双击单片机器件进入下图这个设置界面—>点击打开文件符号—>选择桌面上工程里的hex文件—>打开—>点击OK—>成功。这里没有详细截图,看下图里的左边箭头去找hex文件即可!
在这里插入图片描述
此时可以看到Proteus软件左下角,分别是开始仿真和停止仿真按钮。我们点击开始仿真。
在这里插入图片描述
仿真运行后,可以看到单片机的端口B四位电平,蓝色就是低电平的意思,红色就是高电平的意思,这里就是0101的电平。如果这引脚连接了LED灯,LED灯就可以点亮。由此可见,程序生效了,单片机正常工作中。
在这里插入图片描述

3 单片机基础寄存器操作:

3.1 IO

设置一个端口为输出 TRISA0=0
设置一个端口为输入 TRISA0=1
设置一个端口输出高电平 RA0=1
设置一个端口输出低电平 RA0=0
同时设置8个端口响应使用TRISA PORTA
设置B C D端口类似。

3.2 模拟输入电压读取

设置某个引脚为输入–>打开模拟输入

3.3 外部中断

详细看书。

3.4 定时器中断

详细看书。

3.5 串口UART

详细看书。

3.6 IIC通信

详细看书。

4 实际项目

PIC16F887 单片机 PROTEUS 仿真 C程序 测温系统 TC74 DS18B20
PIC16F887 单片机 PROTEUS 仿真 C程序 信号发生器
PIC16F887 单片机 PROTEUS 仿真 C程序 温控电机
PIC16F887 单片机 PROTEUS 仿真 C程序 数字时钟 万年历 DS1302 阴历显示
PIC16F887 单片机 PROTEUS 仿真 C程序 抢答器
PIC16F887 单片机 PROTEUS 仿真 C程序 可存储电子琴 PIC
PIC16F887 单片机 PROTEUS 仿真 C程序 模拟电话拨号计算器 密码锁
PIC16F887 单片机 PROTEUS 仿真 C程序 电子密码锁
PIC16F887 单片机 PROTEUS 仿真 C程序 智慧门铃呼叫系统 门铃一拖 3
PIC16F887 单片机 PROTEUS 仿真 C程序 病床呼叫系统
PIC16F887 单片机 PROTEUS 仿真 C程序 测温系统 DS18B20 TC74
PIC16F887 单片机 PROTEUS 仿真 C程序 数字点餐系统

5 如何阅读代码

整个程序结构一般如下:

#include <xc.h>
//part 0//
可能会放置一些子函数的声明
C语言嘛,子函数无非就是先声明,后定义。//part 1//
各种杂七杂八的子函数放在这个地方
显示屏子函数
温度传感器子函数
报警判断子函数
按键检测子函数void main( void )
{//part 2//调用一些初始化程序比如单片机引脚要读取按键高低电平,就得把这个引脚设置为输入方向比如定时器中断初始化,设置每隔2ms执行一次中断函数while(1){//part 3//这里是一个死循环体这个位置要写单片机不断重复在做的事情,永不停息比如检测按键输入,有输入了根据输入处理一下比如不断调用温度读取函数,然后把结果显示出来}}//part 3//
这里这个带了interrupt 这个函数就是中断函数
这个函数独立于所有函数之外,单独看这个函数
这个函数是需要被触发的
都是要靠设置单片机寄存器来做到的
比如在main里初始化的时候设置了定时器12ms中断,那么每过2ms就会执行一次high_isr()函数,在函数里面判断寄存器TMR1IF 就可以知道是定时器的2ms事件。
void interrupt high_isr( void )
{if ( TMR1IF ){TMR1IF	= 0;//清除标志位//part 4//这里需要写定时执行的东西,比如我设置了一个变量是秒针倒计时,每一秒就减少1那么我得这么写:变量1 ++;if(变量1加到了500){变量1 = 0;秒针 --;  (变量12ms执行一次减少1500次花费时间1s)}}
}

看懂上面的框架后,我们就可以的代码,我们可以依照以下几个注意点去看程序:
(1)在MPLAB中建立好工程,利用好MPLAB去阅读程序;
(2)MPLAB有个窍门,在工程已经被编译后,我们可以 按住ctrl 然后鼠标左键点函数名字或变量名字去跳转,直接跳转到函数定义的地方。更需要提出的是,在子函数定义处再次ctrl+左键点函数名字,会跳转到子函数声明处。
(3)ctrl+F进入查找,可以通过Next去查看main.c整个文件中的这个查找字符串出现的每一个地方。方便看函数都在哪里用了。
在这里插入图片描述

(4)注重函数或者变量名称+注重分类。比如LCD1602驱动函数就是挨着的一堆,函数名都差不多有个LCD字样。有意识地去多输入一个回车,使得与其他代码间隔远一下,自己更好分清。

(5)建议别从main.c文件的第一行开始看,懂了整个程序结构这个鸭子类型后,单片机上电后就执行main()函数里的,我们就可以直接从main()开始看,先初始化啥啥啥的,然后死循环啥的。别的子函数都是调用,既然在递归,那我们更需要关注最上层,从最上面的调用通过注意点(2)的窍门去看。这样更能注意到 题目功能的实现走向,而不是注意到底层都怎么写的,为什么那么写。

注意:我这里再梳理一下,如何看懂别人的程序是有一个过程的。首先你在脑海里面要有一个程序的大体结构,然后你应该从main()函数开始看,利用鼠标哪里不会点哪里,看看注释帮助自己理解这个函数是在干啥, C语言库函数不理解的直接就baidu学习。其实了解程序结构以后就大概了解整个实现功能的过程,我们无非就是去关注上电之后的初始化过程、主函数在循环处理的过程、中断函数在中断处理哪些事件的过程。最终最终代码就是要实现功能,我们能把代码和功能相关联起来那就成功了!

6 如何把代码放到MPLAB V5.0+xc8 v2.0上工作?

6.1 短暂的回顾

这个话题其实我不太想说,因为以前很多代码资料都是建立在PICC或者xc8 v1.41上(包括大家的教科书上),代码资料多了,做设计就相对来说比较容易,因为这就意味着你可以去找别人的代码资料复制到自己的工程里面去用,并且不用担心因为编译器不同带来的影响(编译器差距太大,会导致最后编译出来的代码不一样,可能我之前在淘宝找的资料能够用xc8 v1.41编译器在实物上运行,修改编译器可能会导致很大的改变,这是我不愿意看到的,不愿意花时间去调试这些bug)。
但总有人问,我来梳理一下怎么去移植。
首先让我们去关注一下xc8 v1.41上面的程序:

#include <xc.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>/* CONFIG1 */
#pragma config FOSC = XT        /* Oscillator Selection bits (XT oscillator: Crystal/resonator on RA6/OSC2/CLKOUT and RA7/OSC1/CLKIN) */
#pragma config WDTE = OFF       /* Watchdog Timer Enable bit (WDT disabled and can be enabled by SWDTEN bit of the WDTCON register) */
#pragma config PWRTE = OFF      /* Power-up Timer Enable bit (PWRT disabled) */
#pragma config MCLRE =ON        /* RE3/MCLR pin function select bit (RE3/MCLR pin function is digital input, MCLR internally tied to VDD) */
#pragma config CP = OFF         /* Code Protection bit (Program memory code protection is disabled) */
#pragma config CPD = OFF        /* Data Code Protection bit (Data memory code protection is disabled) */
#pragma config BOREN = OFF      /* Brown Out Reset Selection bits (BOR disabled) */
#pragma config IESO = OFF       /* Internal External Switchover bit (Internal/External Switchover mode is disabled) */
#pragma config FCMEN = OFF      /* Fail-Safe Clock Monitor Enabled bit (Fail-Safe Clock Monitor is disabled) */
#pragma config LVP = OFF        /* Low Voltage Programming Enable bit (RB3 pin has digital I/O, HV on MCLR must be used for programming) *//* CONFIG2 */
#pragma config BOR4V = BOR40V   /* Brown-out Reset Selection bit (Brown-out Reset set to 4.0V) */
#pragma config WRT = OFF        /* Flash Program Memory Self Write Enable bits (Write protection off) */void main( void )
{while(1){}}
void interrupt high_isr( void )
{}

上面的程序就是一般的xc8 v1.41上面的程序,一起来看一下都有哪些部分。
第1个部分是头文件,其实这个部分更应该放在接下来所要说的第2个部分之后。

#include <xc.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

第2个部分就是编译器预设置,这个部分xc8 v1.41和xc8 v2.0一样规则。#pragma这种指令就是去设置编译器的,告诉编译器应该怎样编译这个c程序。

/* CONFIG1 */
#pragma config FOSC = XT        /* Oscillator Selection bits (XT oscillator: Crystal/resonator on RA6/OSC2/CLKOUT and RA7/OSC1/CLKIN) */
#pragma config WDTE = OFF       /* Watchdog Timer Enable bit (WDT disabled and can be enabled by SWDTEN bit of the WDTCON register) */
#pragma config PWRTE = OFF      /* Power-up Timer Enable bit (PWRT disabled) */
#pragma config MCLRE =ON        /* RE3/MCLR pin function select bit (RE3/MCLR pin function is digital input, MCLR internally tied to VDD) */
#pragma config CP = OFF         /* Code Protection bit (Program memory code protection is disabled) */
#pragma config CPD = OFF        /* Data Code Protection bit (Data memory code protection is disabled) */
#pragma config BOREN = OFF      /* Brown Out Reset Selection bits (BOR disabled) */
#pragma config IESO = OFF       /* Internal External Switchover bit (Internal/External Switchover mode is disabled) */
#pragma config FCMEN = OFF      /* Fail-Safe Clock Monitor Enabled bit (Fail-Safe Clock Monitor is disabled) */
#pragma config LVP = OFF        /* Low Voltage Programming Enable bit (RB3 pin has digital I/O, HV on MCLR must be used for programming) *//* CONFIG2 */
#pragma config BOR4V = BOR40V   /* Brown-out Reset Selection bit (Brown-out Reset set to 4.0V) */
#pragma config WRT = OFF        /* Flash Program Memory Self Write Enable bits (Write protection off) */

第3个部分就是主函数,这个部分xc8 v1.41和xc8 v2.0一样规则。

void main( void )
{while(1){}}

第4个部分中断,这个部分xc8 v1.41和xc8 v2.0命名规则不一样。

void interrupt high_isr( void )
{}

6.2 xc8 v2.0程序结构

下面给出一个xc8 v2.0上面的程序,记住程序结构:


/* CONFIG1 */
#pragma config FOSC = XT        /* Oscillator Selection bits (XT oscillator: Crystal/resonator on RA6/OSC2/CLKOUT and RA7/OSC1/CLKIN) */
#pragma config WDTE = OFF       /* Watchdog Timer Enable bit (WDT disabled and can be enabled by SWDTEN bit of the WDTCON register) */
#pragma config PWRTE = OFF      /* Power-up Timer Enable bit (PWRT disabled) */
#pragma config MCLRE =ON        /* RE3/MCLR pin function select bit (RE3/MCLR pin function is digital input, MCLR internally tied to VDD) */
#pragma config CP = OFF         /* Code Protection bit (Program memory code protection is disabled) */
#pragma config CPD = OFF        /* Data Code Protection bit (Data memory code protection is disabled) */
#pragma config BOREN = OFF      /* Brown Out Reset Selection bits (BOR disabled) */
#pragma config IESO = OFF       /* Internal External Switchover bit (Internal/External Switchover mode is disabled) */
#pragma config FCMEN = OFF      /* Fail-Safe Clock Monitor Enabled bit (Fail-Safe Clock Monitor is disabled) */
#pragma config LVP = OFF        /* Low Voltage Programming Enable bit (RB3 pin has digital I/O, HV on MCLR must be used for programming) *//* CONFIG2 */
#pragma config BOR4V = BOR40V   /* Brown-out Reset Selection bit (Brown-out Reset set to 4.0V) */
#pragma config WRT = OFF        /* Flash Program Memory Self Write Enable bits (Write protection off) */#include <xc.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>void main( void )
{while(1){}}
void __interrupt() ISR( void )
{}

6.3 移植操作指南

1、假如你的程序中含有中断函数,你应该把xc8 v1.41的中断名字改为xc8 v2.0的中断名字。(题外话:做了这一步你的程序基本就OK了,但我也没有调试过实物,不知程序到实物是否正常,建议能不搞xc8 v2.0就别搞,一时的安逸可能带来更多的挫折。)
!!!!据说应该在main()函数之前添加中断的函数声明:void __interrupt() ISR( void ); 不然会乱码。(侧面反应出我们并不熟悉xc8 v2.0,这里行了也不能保证实物正常吧。)
xc8 v1.41的中断名字

void interrupt high_isr( void )

xc8 v2.0的中断名字

void __interrupt() ISR( void )

2、如果你的程序中含有DS1302驱动程序,并且程序中还有下面两句话:

unsigned char		time_rx @ 0x30;                         /* 定义接收寄存器 */
static volatile bit	time_rx7 @ (unsigned) &time_rx * 8 + 7; /* 接收寄存器的最高位 */

这种写法在xc8 v2.0中不再支持,这两句话其实是去取最高位地址bit数据,写法比较高级。你需要把这两句话删除掉。并且你需要把下面的函数修改为下面这个样子(可以直接复制下面这个函数去替换程序中原来的函数,找好位置 别搞错了)。

/****************************************************************************
* 名    称:time_read_1()
* 功    能:读一个字节
* 入口参数:
* 出口参数:
* 说    明:
****************************************************************************/
unsigned char time_read_1()
{int j;                                  /* 设置循环变量 */unsigned char  time_rx;TRISC4 = 1;                             /* 设置数据口方向为输入 */for ( j = 0; j < 8; j++ )               /* 连续读取8bit */{sclk		= 0;            /* 拉低时钟信号 */time_rx		= time_rx >> 1; /* 接收寄存器右移1位 */if(i_o){time_rx |= 0x80;}sclk		= 1;            /* 拉高时钟信号 */}TRISC4	= 0;                            /* 恢复数据口方向为输出 */sclk	= 0;                            /* 拉低时钟信号 */return(time_rx);                        /* 返回读取到的数据 */
}

3、你或许更应该将编译器预设置部分的代码放到程序的最开始,但我个人认为其实没什么影响。

4、如果你在移植操作中遇到更多的报错信息,可以告诉我。我的处理方式也很简单,我会根据软件下面的报错信息找到对应的报错点,然后根据经验修改报错点程序即可。

7 常用的代码解释

看到这里,你应该有一个基本观念,不要拿“我们没学过”当借口,遇到程序看不懂就知道退缩,怎么学也学不会。
多找资料,多复习C语言,遇到问题敢于写个小程序做做实验。你自己想要写出自己的程序的第一步,就是模仿学习别人的程序。

7.1 关于LCD1602

LCD1602使用LCD_WRITE()函数执行写入命令操作或者写入数据操作。
写入命令0x80+x,代表想要显示的起始位置是LCD1602的第0行,第x列。(一共有2行,16列,x可以等于0到15,y可以等于0到1)。
写入命令0xC0+x,代表想要显示的起始位置是LCD1602的第1行,第x列。
char *s是一个指针,指向一个字符串首地址的话,while (*s)会一直判断当前是不是为空,不为空就向1602写入指针指向的字符 LCD_WRITE(*s, DATA);,写入后指针后移一个字符 s++。
举例 lcd1602_write_str(3,1,“hello”); 就是想在第3列,第1行开始显示,显示一个字符串hello。指针最初指向’h’,写入后后移,直到指针指向空。

/* 写字符串 */
void lcd1602_write_str(unsigned char x, unsigned char y, char *s)
{if (y == 0){LCD_WRITE(0x80 + x, COM);//写入命令}else{LCD_WRITE(0xC0 + x, COM);//写入命令}while (*s){LCD_WRITE(*s, DATA);//写入数据s++;}
}

7.2 memset清空 sprintf装填

学了void lcd1602_write_str(unsigned char x, unsigned char y, char *s)函数后,写显示函数就简单了。
你会定义一个数组,比如是 buffer[16]。
当你想显示hello的时候,你可以这么写:

buffer[0]='h';
buffer[1]='e';
buffer[2]='l';
buffer[3]='l';
buffer[4]='o';
buffer[5]=0; //必须给0,指针指到这里认出0就代表空了
lcd1602_write_str(3,1,buffer);//指针指向数组的首位,然后指针一直后移,最终写入完整hello

但上面的方法不方便,比如你想显示一个变量abc,你得这么写:

int abc=54;
buffer[0]='0'+abc%100/10;//百分号是取余运算,/是整除运算,可百度。加'0'是为了变成ascii码。
buffer[1]='0'+abc%10;
buffer[2]=0;
lcd1602_write_str(3,1,buffer);

C语言发明者就发明了一个通用函数sprintf,这让这个操作简单了。
比如你想把字符串“hello”装入数组里,你可以直接:

sprintf(buffer, "hello");//装填

C语言就会把字符串一个一个填入数组,这个时候你就可以调用类似于lcd1602_write_str(3,1,buffer);这样去显示了。
比如你想把abc变量变成字符串然后写入数组,你可以直接:

sprintf(buffer, "hello %d",abc);//装填  %d是十进制表示的意思 
sprintf(buffer, "hello %d  %d",abc, abc);//可以一次装填多个变量

第一个参数是数组指针 buffer
第二个参数是字符串样式
第三个参数和后面参数是一些变量
这个时候还有个问题,就用sprintf(buffer, "hello");//装填举例,执行这句话后数组里是变成字符串了,此时有:

buffer[0]='h';
buffer[1]='e';
buffer[2]='l';
buffer[3]='l';
buffer[4]='o';

但是并不能保证数组里面其他的元素是0!!
C语言发明者就搞了一个memset函数,能够初始化一切数组。
此时就可以:

memset(buffer, 0, sizeof(buffer));

第一个参数是数组指针 buffer
第二个参数是想把数组里面所有元素初始化为0
第三个参数是想初始化多长的元素,sizeof(buffer)表示想初始化数组里所有元素。

1 参考书籍:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


http://chatgpt.dhexx.cn/article/kxVkwaYZ.shtml

相关文章

通俗易懂讲PIC单片机:从一窍不通到入门进步

单片机入门不难------谈PIC系列&#xff08;转自矿石收音机论坛---崂山&#xff09;十年前的老帖子&#xff0c;讲得通俗易懂&#xff0c;分享之。 请看图1 这个8条腿的小螃蟹就是我们的第一顿饭&#xff0c;只要把它吃下去&#xff0c;以后的大餐就好办了。第1、8条腿接电源 …

PIC单片机应用开发实践教程(五): 烧录器简介

源码基于 PIC16F15355开发板&#xff0c;想了解详情&#xff0c;请点 PIC16F15355开发板 ​​​​​​​ PIC单片机&#xff0c;无论是8位的10/12/16/18系列&#xff0c;还是16位PIC24/dsPIC33系列&#xff0c;常用的烧录器如下&#xff1a;PICkit3&#xff0c;PICkit4&#…

PIC单片机入门_C语言编程技术

1.为什么也是C语言&#xff1f; 用C 语言来开发单片机系统软件最大的好处是编写代码效率高、软件调试直观、维护升级方便、代码的重复利用率高等&#xff0c;因此C 语言编程在单片机系统设计中越来越广泛的运用。PIC 单片机的软件开发&#xff0c;同样可以用C 语言实现。 Micro…

PIC单片机与PIC单片机C语言编程简介

对于计算机学院与电子学院相关的同学来说&#xff0c;单片机一定不是一个陌生的概念。在大学的学习生涯中&#xff0c;经常用于教学的是MCS-51系列单片机。其实&#xff0c;除了MCS-51单片机外&#xff0c;还有一类单片机——PIC单片机。 PIC单片机&#xff0c;英文名为Periphe…

PIC单片机应用开发实践教程(三): MCU配置位与烧录

1 编译 工程建好并把相应的 .c和.h文件都加载到工程后&#xff0c;如下图 试试编译&#xff0c;如果没有语法错误&#xff0c;编译结果如下 到这里&#xff0c;是不是可以进行烧录了呢&#xff1f;不急&#xff0c;还有很重要的一个步骤&#xff0c;MCU配置位的设置&#xff0…

PIC单片机应用开发实践教程(一):MPLAB X IDE 开发环境安装

源码基于 PIC16F15355开发板&#xff0c;想了解详情&#xff0c;请点 PIC16F15355开发板 1 准备电脑一台 2 下载开发环境 MPLAB-X-IDE 点Download后&#xff0c;自动下载。 3 下载C编译器&#xff08;以8位MCU用的xc8编译器为例&#xff09; MPLAB XC8 Compiler 4 安装MP…

PIC单片机入门教程(一)—— 准备工作

PIC单片机入门教程&#xff08;一&#xff09;—— 准备工作 1、电脑一台&#xff08;推荐运行Windows 7 旗舰版 64位系统&#xff09; 2、选择合适的烧录/调试工具 2.1 “Device Support.html”文件列举了所有器件能支持哪些烧录/调试工具&#xff0c;文件官方版本说明包里 下…

PIC单片机入门教程(三)—— 安装编译器(MPLAB XC Compilers)

PIC单片机入门教程&#xff08;三&#xff09;—— 安装编译器&#xff08;MPLAB XC Compilers&#xff09; 1、下载编译器&#xff08;MPLAB XC Compilers&#xff09; XC8、XC16和XC32对应8位、16位和32位PIC单片机&#xff0c;按实际使用的单片机选择下载最新版本即可。 截…

PIC单片机入门教程(四)—— 第一个工程

PIC单片机入门教程&#xff08;四&#xff09;—— 第一个工程 1、新建工程 1.1 菜单栏“文件”->“新建项目” 1.2 “Microchip嵌入式”->“独立项目”->“下一步” 1.3 在器件栏直接输入你的单片机型号&#xff0c;这里以PIC12F675为例。输入“PIC12F675”->“下…

PIC单片机入门_指令系统

1.前文回顾 前面学习了PIC单片机的系统框架&#xff0c;也介绍了程序存储器、数据存储器的组织形式。这里需要补充一点的就是寻址方式&#xff0c;之前仅仅提到了立即数寻址、直接寻址。其实还有几个比较重要的寻址方式&#xff0c;PC相对寻址&间接寻址&#xff01; 1.1 PC…

Demand management

需求管理&#xff08;Demand Management&#xff09;用于连接计划需求&#xff0c;销售需求和物料计划&#xff08;MPS和MRP&#xff09;。

Data Quality Services

Data Quality Services 简介 SQL Server 2012 其他版本 使用 Data Quality Services (DQS) 提供的数据质量解决方案&#xff0c;数据专员或 IT 专业人员可以维护数据的质量并确保数据满足业务使用的要求。 DQS 是一种知识驱动型解决方案&#xff0c;该解决方案通过计算机辅助方…

MySql: In aggregated query without GROUP BY...;this is incompatible with sql_mode=only_full_group_by

错误原因 这是MySql5.7以上的版本特性导致的。 解决方案 执行下面这段代码 SET sql_mode(SELECT REPLACE(sql_mode,ONLY_FULL_GROUP_BY,));运行一下然后就可以了&#xff0c;完。

Terms-level Query之Exists Query

​Exists Query属于Term-level Query查询, 查询某字段值不为空的文档。脑图如下&#xff1a; 内容说明&#xff1a; 本文内容同微信公众号【凡登】&#xff0c;关注不迷路&#xff0c;欢迎加入一起共同学习。原文链接:Terms-level Query之Exists Query 目录 一、语法&#xf…

Android Query managedQuery

今天说一下以下两种方式query数据&#xff1a; Java代码 Cursor c1 mContext.getContentResolver().query(uri, projection, selection, selectionArgs, sortOrder); Cursor c2 mActivity.managedQuery(uri, projection, selection, sortOrder); 使用方法一&#xf…

Android开发managedQuery方法过时如何解决

今天在获取手机相册照片的时候用到了managedQuery&#xff0c;然后发现managedQuery过时了&#xff0c;如下图所示&#xff1a; 于是就百度了一下解决办法&#xff0c;其实也挺简单的。用getContentResolver().query()来代替managerQuery()&#xff0c;参数什么的都一样。 如上…

括号匹配的检验

[TO在这/.按“3.2.2 括号匹配的检验”中的思路&#xff0c;写一个函数“bool check(char* line)” //检查输入的字符串line中的括号是否匹配&#xff0c;不匹配则check函数返回false&#xff0c;否则返回true #include <stdio.h> #include <stdlib.h> #include &l…

括号匹配C语言实现

若你掌握以下知识&#xff0c;你可以更好地理解此篇文章&#xff1a; 1.C语言基本语法。 2.栈的核心思想与栈的构建。 分割线/ 相信看此篇文章的朋友很多是从书本过来的&#xff0c;书本那段描述真的晦涩难懂&#xff0c;什么紧迫性123456的&#xff0c;什么被需要&#xff0…

c语言括号匹配的检验,检验括号匹配的算法

用栈实现检验括号匹配的算法没啥具体描述&#xff0c;数据结构的知识&#xff0c;急用&#xff0c;有重赏 思想是 先进栈&#xff0c;获取第一个半边括号&#xff0c;标记一下&#xff0c;继续进栈直到获取到第二个与之匹配的另一外括号&#xff0c;然后出栈&#xff0c;取出内…

栈和括号匹配

栈是一种符合先进后出原则的数据结构 主要操作氛围进栈和弹栈。规则是栈顶元素先弹出而后进栈&#xff0c;进栈就是一个新的元素取代原本的栈顶元素。 栈可以用来进行最基本的括号匹配操作&#xff0c;栈的图示为&#xff1a;&#xff08;转载&#xff09; 具体代码如下 //定…