技术标签: c语言比用delay更好的延时
本文是讲座《单片机C 语言程序设计》的结束篇,为了帮助大家更好地掌握前面所学的知识,我们将归纳性地介绍初学者用C 语言编辑PIC 单片机实用程序时应具备的思维方法和基本知识,并通过下面的实例进行一次小结,以期对大家今后深入学习PIC 单片机C 语言程序设计有所帮助。
十六、PIC单片机C语言程序的组成
一个完整的PIC 单片机C 语言源程序应包括:包含头文件、变量定义、常量说明、函数定义、主函数main( )、若干个其他功能函数、各种功能C 语句,以及已定义的函数和函数体、注释等部分组成。
说明:对PIC 单片机中级或中级以下的产品,其头文件是#include和#include; 对高级产品,如PIC18F452 器件,其头文件是#include和#include< pic18fxx2.h>。
C 程序的运行,总是从主函数main( ) 开始(可以通过模拟仿真直接观察到),由主函数调用其他函数,其他函数也可互相调用, 如此运行工作。而C 语句,又可按其执行方式的不同而分为顺序结构、选择结构和循环结构等。这里的顺序结构, 是指程序按语句的顺序逐条执行;选择结构, 是指程序根据相关条件选择的执行顺序; 循环结构, 是指程序根据某条件的存在执行一段程序,直到条件消失为止,若该条件永远存在,就形成无限循环。
1. 延时函数的三种表达式
用汇编语言编辑一个较大的PIC 单片机程序时,一般分为多个程序模块,每个模块的子程序实现一个特定的功能。而用C 语言编辑该程序时,模块的功能是用函数实现的,即函数相当于汇编语言的子程序。下面我们以延时函数应用的实例,来说明PIC 单片机C 语言程序的基本组成格式。
延时函数是PIC 单片机源程序中出现频率较高的函数,而且具有相同功能的延时函数也有多种形式,我们选择常用的三种延时函数进行讨论。
所引用的三种延时函数都是由循环控制语句——while、do_while 和for 等实现的。
(1)带形式参数的由for 语句组成的延时函数。
void delay(unsigned int k)
{
unsigned int i, j;
fir(i=0;i<=81;i++)
fir(j=0;j<=k;j++)
cONtinue;
}
该延时函数由两个for 语句组成,第一个for语句中的81 是笔者设置的常数(可任意设定),用于使延时值增加; 第二个for 语句中的k 是在程序中主函数main( ) 调用delay(k) 时,由用户给定的值,k 值不同,延时时间就不等, 所以该延时函数可在一个C 程序中实现不同的多个延时量,显然比汇编语言延时子程序简单多了。在延时量要求较短时, 该延时函数种的两个for 语句的功能可用一个for 语句来实现。
(2)带形式参数的由while 循环语句组成的延时函数。
Void deley(unsigned long int k)
{
Unsigned long int d=k;
While(--d)
{;
}
{
此延时函数简单、容易记忆。使用时,在程序中主函数main( ) 调用delay(k) 时,由用户给定不同的k 值,亦可实现多种延时值。
(3)带形式参数的由do-while 语句组成的延时函数。
Void delay(unsigned long int k)
{
Unsigned int long j=o;
do {
j++;
}
While(j < =k);
j=o;
}
该延时函数简单易记。使用时,在程序中主函数main( ) 调用delay(k) 时,由用户给定不同的k 值,即可实现多种延时值。
需要说明的是,上述由while 循环语句和由do-while 语句组成的延时函数中的形式参数,不一定用长整型(long ink)。
⒉ 电路功能相同形式不同的四种C 程序
下面介绍利用PIC16F84A 单片机的PORTB端口外接的8 只LED, 采用四种C 程序控制端口的LED 灯,来说明编辑C 语言程序时的基本格式及其灵活性。电路参见《电子制作》2009 年9期《单片机C 语言程序设计(1)》一文中的图1,程序流程如图64 所示,采用的是无限循环工作方式。
图64
(1)C 程序一,文件名为pic09.c, 清单如下:
#include // 头文件
void delay(unsigned long int K)
// 延时函数开始
{
unsigned int long j=0;
// 说明语句
do
// 由do-while 组成的延时执行语句
{
j++;
}
while(j<=K);
j=0;
}
main( ) // 主函数开始
{
TRISB=0x00;
// 设置PORTB 口全为输出
INTCON=0x00; // 关闭所有中断
PORTB=0x00; //RB 口先送低电平
while(1) // 永久循环开始
{
PORTB=0x55;
//RB 口外接LED 其1、3、5、7 点亮
delay(45000);
// 点亮的LED 延时1 秒后关闭
PORTB=0xAA;
//RB 口外接LED 其2、4、6、8 点亮
delay(98000);
// 点亮的LED 延时2 秒后关闭
PORTB=0xFF; //RB 口外接LED 全亮
delay(155000);
// 全亮的LED 延时3 秒后关闭
}
}[page]
说明:a. 上述程序中,延时函数带形式参数K,并由do-while 语句组成。
b. 主函数main() 调用delay(k) 时,其K 分别是45000(1 秒)、98000(2 秒)、和155000(3秒)。
c.LED 灯点亮时的无限循环,由while(1) 语句完成。
(2)C 程序二,文件名为pic10.c, 清单如下:
#include // 头文件
void delay( K ) // 延时函数
unsigned long int K;
// 形参数(k) 说明
{
unsigned long int d=K;
// 说明语句
while(--d)
// 由while 组成的延时执行语句
{;
}
}
main( ) // 主函数开始
{
TRISB=0x00
// 设置PORTB 口全为输出
INTCON=0x00; // 关闭所有中断
PORTB=0x00; //RB 口先送低电平
loop: // 语句标号(无限循环)
PORTB=0x55;
//RB 口外接LED 其1、3、5、7 点亮
delay(37000);
// 点亮的LED 延时1 秒后关闭
PORTB=0xAA;
//RB 口外接LED 其2、4、6、8 点亮
delay(74000 );
// 点亮的LED 延时2 秒后关闭
PORTB=0xFF; //RB 口外接LED 全亮
delay(111000);
// 全亮的LED 延时3 秒后关闭
goto loop; // 跳转到loop 处循环
}
说明:a. 上述程序中,延时函数带形参数k,且由while 语句组成。
b. 主函数main( ) 调用delay(k) 时,其k 分别是37000(1 秒)、74000(2 秒)和1110000(3 秒)。
c. LED 灯点亮时的无限循环,由goto 无条件转移执行语句完成。其中loop 为语句标号。对goto 语句使用时应慎重,在简单的C 程序中使用goto 语句是必要的,但编辑复杂的C 程序结构,会使程序的可读性变差。
(3) C 程序三,文件名为pic11.c, 清单如下:
#include // 头文件
unsigned int h; // 无符号的整型变量
void delay(unsigned long int M)
// 延时函数开始
{
unsigned int long i,j; // 说明语句
for(i=0;i<=81;i++)
// 由两个for 语句组成的
for(j=0;j<=M;j++) // 延时执行语句
continue; // 继续循环
}
main( ) // 主函数开始
{
TRISB=0x00;
// 设置PORTB 口全为输出
INTCON=0x00; // 关闭所有中断
PORTB=0x00; //RB 口先送低电平
h=0; // 给h 赋置0
do
// do-while 语句开始循环
{
PORTB=0x55;
//RB 口外接LED 其1、3、5、7 点亮
delay(500);
// 点亮的LED 延时1 秒后关闭
PORTB=0xAA;
//RB 口外接LED 其2、4、6、8 点亮
delay(1000);
// 点亮的LED 延时2 秒后关闭
PORTB=0xFF; // RB 口外接LED 全亮
delay(1500);
// 全亮的LED 延时3 秒后 关闭
h++; // h 自增量
}
while(h<=100); //h 自增不满足条件时
h=0; // 给h 赋值0
return; // 返回
}
说明:a. 上述程序中,延时函数带形参数M,并由二个for 语句组成(可以是多个for 语句或一个for 语句)。
b. 主函数main( ) 调用delay(M) 时,M 值分别是500(1 秒)、1000(2 秒)和1500(3 秒)。
c. LED 灯点亮时的无限循环由do_while 语句完成,其while(h < =100) 中的100 可任意选取大于0 的其他值。
(4)C 程序四,文件名为pic12.c,清单如下:
#include // 头文件
void delay(unsigned long int M)
// 延时函数开始
{
unsigned int long j; // 说明语句
for(j=0;j<=M;j++)
// 由一个for 语句组成的延时语句
continue; //for 条件满足继续循环
}
void light1( );
// 声明RB 口点LED 灯函数1
void light2( );
// 声明RB 口点LED 灯函数2
void light3( );
// 声明RB 口点LED 灯函数3
main( ) // 主函数开始
{
TRISB=0x00;
// 设置PORTB 口全为输出
INTCON=0x00; // 关闭所有中断
PORTB=0x00; //RB 口先送低电平
while(1) // 永久循环开始
{
light1( ); // 调用LED 灯函数
delay(45000); // 调用延时函数(1 秒)
light2( ); // 调用LED 灯函数2
delay(95000); // 调用延时函数(2 秒)
light3( ); // 调用LED 灯函数3
delay(145000); // 调用延时函数(3 秒)
}
}
void light1( ) //LED 灯函数1
{
PORTB=0x55;
// RB 口外接LED 其1、3、5、7 点亮
}
void light2( ) //LED 灯函数2
{
PORTB=0xAA;
//RB 口外接LED 其2、4、6、8 点亮
}
void light3( ) //LED 灯函数3
{
PORTB=0xFF; //RB 口外接LED 全亮
}
[page]说明:a. 上述程序中,延时函数带形参数M,并由一个for 语句组成的。
b. 主函数main( ) 调用delay(M) 时, 其M 值分别是45000(1 秒)、95000(2 秒) 和145000(3 秒)。
c. LED 灯点亮时的无限循环,由while 语句完成。
d. 上述程序都以LED 的各功能函数lightl();light2( );light3( ) 完成。程序运行时,由主函数main( ) 调用各LED 的功能函数和延时函数,此方法是编辑复杂C 程序所必备的。
3. PIC 单片机端口的位定义
PIC 单片机是一种系列产品, 其端口数和端口的位与具体型号有关。如PIC16F877 的端口有PORTA ~ PORTE, 端口的位不都是8位, 其PORTA 口只有6 位(RAO ~ RA5),PORTAB、BORTC 和PORTD 是8 位, 分别为RB0 ~ RB7、RC0 ~ RC7、RD0 ~ RD7。在编辑C 程序时,要访问上述端口的某个位,必须先把这一位的地址确定下来, 这可通过@add(address) 结构和bit 关键字来实现,其中@是地址标识符、add(address) 是绝对地址。利用上述地址符,可对PIC 单片机端口的位进行定义,尔后便可随意对端口的位进行访问。下面是对PIC16F84A 的PORTB 口进行位定义的语句:
# dafine PORTBIT ( add , bit ) ( ( unsigned )
(&add)*8+(bit))
Satic bit PORTB_0@PORTBIT(PORTB,0);//定义PORTB 的0 位
Satic bit PORTB_1@PORTBIT(PORTB,1)//定义PORTB 的1 位
……
Static bit PORTB_7@PORTBIT(PORTB,7);//定义PORTB 的7 位
其中“&”和”*”符号,在C 语言中是作为按位运算符用的,而8 是指8 位。在编辑PIC 单片机C 程序时,一旦某个端口,如PORTB,定义后, 其对应位(bit) 还可写成RBO、RB1、RB2、RB3…RB7, 以使程序代码简化。
有关端口位定义后的应用,还可参看《单片机C 语言程序设计(6)》一文中的程序pic06.c。
4. LED 数码显示函数的应用
下面以倒计数、倒计时C 程序实例, 说明LED 数码显示函数display(x) 的应用。
(1)硬件电路利用PIC16F84A 的4 位LED 数码显示电路( 参见《单片机C 语言程序设计(4)》一文中的图3、图4) 制作2 位数码管(另两位不用)的99 ~ 0 倒计数、倒计时显示。倒计数以秒为单位,倒计时以分为单位,只要有显示函数display(),其计数、计时程序的格式相同。
(2) 99 ~ 0(以分钟计)的C 源程序清单如下,程序名为pic13.c。
#include// 头文件
# define PORTAIT ( add , bit ) ( ( unsigned )
(&add)*8+(bit))
static bit PORT _ 2@ PORTAIT ( PORTA , 2 ) ;
//PORTA 口位定义
static bit PORT_3 @PORTAIT(PORTA,3);
static bit PORT_4 @PORTAIT(PORTA,4);
unsigned int x=0; // 无符号的整形变量
void delay(unsigned long int k )
// 延时函数开始
{
unsigned long int i; // 说明语句
for(i=0;i<=k;i++) //for 执行语句
continue; // 继续循环
}
void display(unsigned int x)
// 数码管LED 显示函数
{
unsigned int d=5700,unit_bit,ten_bit;
// 无符号整型变量D,个位、十位
unsigned char SEG7[10]={0xc0,0xf9,0xa4,
//0 ~ 9 的7 段码数组
0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
unit_bit=x%10; //picc 可识别个位数
ten_bit=x/10%10; //picc 可识别十位数
while(d>0) //while 语句开始
{
PORTA=0x1F;
//PORTA 口的低位输出高电平
PORTB=SEG7[unit_bit];
// 个位字段码数组送B 口
RA3=0; //RA3 赋值0,LED 个位显示
delay(200); // 延时以便观察
RA3=1; //RA3 赋值1,LED 个位数灭
delay(2); // 短延时
PORTB=SEG7[ten_bit];
// 十位字段码数组送B 口
RA2=0; //RA2 赋值0,LED 十位数显示
delay(200); // 延时以使观察
RA2=1; //RA2 赋值1,LED 十位数灭
delay(2); // 短延时
d--; //d 自减量
}
}
void main( ) // 主函数开始
{
TRISB=0x00; //B 口全为输出
TRISA=0x10; //A 口低4 位为输出
PORTB=0x40; // 给B 口低位输出0
INTCON=0x00; // 关闭所有中断
PORTA=0x10; //A 口低位输出0
x=99; // 给整形变量x 赋值99
while(RA4) // 显示起动信号
{; //RA4 为0,计时开始
}
while(1) // while 循环语句开始
{
display(x); // 调用显示函数
x--; //x 自减
if(x==-1) // 若x 自减到-1
x=99; // 给x 赋值99
}
}
说明:a. 对上述的C 源程序,只需将显示函数display(x) 中的无符号整型变量d(unsignedint d) 从5700 改为95,即可变成以秒为单位的99 ~ 0 倒计数程序,因为d 值决定了数码管显示的个位时间 ( 具有唯一性)。
b. 若要使用上述程序, 且对计时( 分或秒)的精度有严格要求时,可对整型变量d 值(57000)以标准时钟为准进行微调,以实现高精度的分或秒定时。
c. 上述所有PIC 单片机的C 源程序,都是可执行的, 初学者可放心使用。
5. 关于PIC 单片机c 语言程序SIM 软件仿真的问题
在《单片机C 语言程序设计(11)》、《单片机C 语言程序设计(12)》中,详细介绍了C 程序的SIM 软件仿真过程。软件仿真对初学者编辑PIC 单片机C 语言程序十分有用, 利用它不仅可以观察到程序运行过程,而且可以发现程序中的问题,即使是已掌握了PIC 编程技术的专业人员,也常通过SIM 软件仿真来找出程序中的问题。
结束语
上面介绍的延时函数的三种表达式、电路功能相同形式不同的四种C 程序、端口的位定义、LED 数码显示函数和C 语言程序SIM 软件仿真问题等内容,均是初学PIC 单片机用C 语言编辑源程序的基本知识,大家要理解其内容,最好能熟记和背诵。在此基础上,还要自己独立想一些简单电路功能,用PIC 单片机C 语言完成(一定是编译成功可执行的程序)。之后,即可进一步学习C 语言中的运算符、结构、联合、A/D 转换、串行通信等内容。学习时,仍应以编辑可执行的实用程序为目标。
文章浏览阅读347次。idea shift f6 快捷键无效_idea shift +f6快捷键不生效
文章浏览阅读135次。Ecmacript 中没有DOM 和 BOM核心模块Node为JavaScript提供了很多服务器级别,这些API绝大多数都被包装到了一个具名和核心模块中了,例如文件操作的 fs 核心模块 ,http服务构建的http 模块 path 路径操作模块 os 操作系统信息模块// 用来获取机器信息的var os = require('os')// 用来操作路径的var path = require('path')// 获取当前机器的 CPU 信息console.log(os.cpus._node模块中有很多核心模块,以下不属于核心模块,使用时需下载的是
文章浏览阅读10w+次,点赞435次,收藏3.4k次。SPSS 22 下载安装过程7.6 方差分析与回归分析的SPSS实现7.6.1 SPSS软件概述1 SPSS版本与安装2 SPSS界面3 SPSS特点4 SPSS数据7.6.2 SPSS与方差分析1 单因素方差分析2 双因素方差分析7.6.3 SPSS与回归分析SPSS回归分析过程牙膏价格问题的回归分析_化工数学模型数据回归软件
文章浏览阅读7.5k次。如何利用hutool工具包实现邮件发送功能呢?1、首先引入hutool依赖<dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.7.19</version></dependency>2、编写邮件发送工具类package com.pc.c..._hutool发送邮件
文章浏览阅读867次,点赞2次,收藏2次。docker安装elasticsearch,elasticsearch-head,kibana,ik分词器安装方式基本有两种,一种是pull的方式,一种是Dockerfile的方式,由于pull的方式pull下来后还需配置许多东西且不便于复用,个人比较喜欢使用Dockerfile的方式所有docker支持的镜像基本都在https://hub.docker.com/docker的官网上能找到合..._docker安装kibana连接elasticsearch并且elasticsearch有密码
文章浏览阅读370次。算法分析的概念程序和算法的区别算法是对问题解决的分步描述。程序是采用某种编程语言实现的算法算法分析主要就是从计算资源消耗的角度来评判和比较算法更高效利用计算资源,或者更少占用计算资源的算法就是好算法。计算资源指标一种是算法解决问题过程中需要的存储空间或内存存储空间收到问题自身数据规模的变化影响要区分哪些存储空间是问题本身描述所需,哪些是算法占用不容易另一种是算法的执行时间可以对程序进行实际运行测试,获得真实的运行时间运行时间检测Python中有一个time模块,可以获取计算机系统当前_所谓“变位词”是指两个词之间存在组成字母的重新排列关系。如:heart和earth,pyth
文章浏览阅读7.9k次。//// ViewController.swift// Day_10_Timer//// Created by dongqiangfei on 2018/10/15.// Copyright 2018年 飞飞. All rights reserved.//import UIKitclass ViewController: UIViewController { ..._swift timer 暂停
文章浏览阅读986次,点赞2次,收藏2次。1.硬性等待让当前线程暂停执行,应用场景:代码执行速度太快了,但是UI元素没有立马加载出来,造成两者不同步,这时候就可以让代码等待一下,再去执行找元素的动作线程休眠,强制等待 Thread.sleep(long mills)package com.example.demo;import org.junit.jupiter.api.Test;import org.openqa.selenium.By;import org.openqa.selenium.firefox.Firefox.._元素三大等待
文章浏览阅读3k次,点赞4次,收藏14次。Java软件工程师职位分析_java岗位分析
文章浏览阅读2k次。Java:Unreachable code的解决方法_java unreachable code
文章浏览阅读1w次。1、html中设置标签data-*的值 标题 11111 222222、点击获取当前标签的data-url的值$('dd').on('click', function() { var urlVal = $(this).data('ur_如何根据data-*属性获取对应的标签对象
文章浏览阅读6.9w次,点赞73次,收藏463次。1.前序创建#include<stdio.h>#include<string.h>#include<stdlib.h>#include<malloc.h>#include<iostream>#include<stack>#include<queue>using namespace std;typed_二叉树的建立