c语言比用delay更好的延时,PIC单片机C语言程序设计(15)-程序员宅基地

技术标签: 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 所示,采用的是无限循环工作方式。

363739a6edba67a05bdb72c3cd6800dd.png

图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 转换、串行通信等内容。学习时,仍应以编辑可执行的实用程序为目标。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_39916511/article/details/117236319

智能推荐

分布式光纤传感器的全球与中国市场2022-2028年:技术、参与者、趋势、市场规模及占有率研究报告_预计2026年中国分布式传感器市场规模有多大-程序员宅基地

文章浏览阅读3.2k次。本文研究全球与中国市场分布式光纤传感器的发展现状及未来发展趋势,分别从生产和消费的角度分析分布式光纤传感器的主要生产地区、主要消费地区以及主要的生产商。重点分析全球与中国市场的主要厂商产品特点、产品规格、不同规格产品的价格、产量、产值及全球和中国市场主要生产商的市场份额。主要生产商包括:FISO TechnologiesBrugg KabelSensor HighwayOmnisensAFL GlobalQinetiQ GroupLockheed MartinOSENSA Innovati_预计2026年中国分布式传感器市场规模有多大

07_08 常用组合逻辑电路结构——为IC设计的延时估计铺垫_基4布斯算法代码-程序员宅基地

文章浏览阅读1.1k次,点赞2次,收藏12次。常用组合逻辑电路结构——为IC设计的延时估计铺垫学习目的:估计模块间的delay,确保写的代码的timing 综合能给到多少HZ,以满足需求!_基4布斯算法代码

OpenAI Manager助手(基于SpringBoot和Vue)_chatgpt网页版-程序员宅基地

文章浏览阅读3.3k次,点赞3次,收藏5次。OpenAI Manager助手(基于SpringBoot和Vue)_chatgpt网页版

关于美国计算机奥赛USACO,你想知道的都在这_usaco可以多次提交吗-程序员宅基地

文章浏览阅读2.2k次。USACO自1992年举办,到目前为止已经举办了27届,目的是为了帮助美国信息学国家队选拔IOI的队员,目前逐渐发展为全球热门的线上赛事,成为美国大学申请条件下,含金量相当高的官方竞赛。USACO的比赛成绩可以助力计算机专业留学,越来越多的学生进入了康奈尔,麻省理工,普林斯顿,哈佛和耶鲁等大学,这些同学的共同点是他们都参加了美国计算机科学竞赛(USACO),并且取得过非常好的成绩。适合参赛人群USACO适合国内在读学生有意向申请美国大学的或者想锻炼自己编程能力的同学,高三学生也可以参加12月的第_usaco可以多次提交吗

MySQL存储过程和自定义函数_mysql自定义函数和存储过程-程序员宅基地

文章浏览阅读394次。1.1 存储程序1.2 创建存储过程1.3 创建自定义函数1.3.1 示例1.4 自定义函数和存储过程的区别1.5 变量的使用1.6 定义条件和处理程序1.6.1 定义条件1.6.1.1 示例1.6.2 定义处理程序1.6.2.1 示例1.7 光标的使用1.7.1 声明光标1.7.2 打开光标1.7.3 使用光标1.7.4 关闭光标1.8 流程控制的使用1.8.1 IF语句1.8.2 CASE语句1.8.3 LOOP语句1.8.4 LEAVE语句1.8.5 ITERATE语句1.8.6 REPEAT语句。_mysql自定义函数和存储过程

半导体基础知识与PN结_本征半导体电流为0-程序员宅基地

文章浏览阅读188次。半导体二极管——集成电路最小组成单元。_本征半导体电流为0

随便推点

【Unity3d Shader】水面和岩浆效果_unity 岩浆shader-程序员宅基地

文章浏览阅读2.8k次,点赞3次,收藏18次。游戏水面特效实现方式太多。咱们这边介绍的是一最简单的UV动画(无顶点位移),整个mesh由4个顶点构成。实现了水面效果(左图),不动代码稍微修改下参数和贴图可以实现岩浆效果(右图)。有要思路是1,uv按时间去做正弦波移动2,在1的基础上加个凹凸图混合uv3,在1、2的基础上加个水流方向4,加上对雾效的支持,如没必要请自行删除雾效代码(把包含fog的几行代码删除)S..._unity 岩浆shader

广义线性模型——Logistic回归模型(1)_广义线性回归模型-程序员宅基地

文章浏览阅读5k次。广义线性模型是线性模型的扩展,它通过连接函数建立响应变量的数学期望值与线性组合的预测变量之间的关系。广义线性模型拟合的形式为:其中g(μY)是条件均值的函数(称为连接函数)。另外,你可放松Y为正态分布的假设,改为Y 服从指数分布族中的一种分布即可。设定好连接函数和概率分布后,便可以通过最大似然估计的多次迭代推导出各参数值。在大部分情况下,线性模型就可以通过一系列连续型或类别型预测变量来预测正态分布的响应变量的工作。但是,有时候我们要进行非正态因变量的分析,例如:(1)类别型.._广义线性回归模型

HTML+CSS大作业 环境网页设计与实现(垃圾分类) web前端开发技术 web课程设计 网页规划与设计_垃圾分类网页设计目标怎么写-程序员宅基地

文章浏览阅读69次。环境保护、 保护地球、 校园环保、垃圾分类、绿色家园、等网站的设计与制作。 总结了一些学生网页制作的经验:一般的网页需要融入以下知识点:div+css布局、浮动、定位、高级css、表格、表单及验证、js轮播图、音频 视频 Flash的应用、ul li、下拉导航栏、鼠标划过效果等知识点,网页的风格主题也很全面:如爱好、风景、校园、美食、动漫、游戏、咖啡、音乐、家乡、电影、名人、商城以及个人主页等主题,学生、新手可参考下方页面的布局和设计和HTML源码(有用点赞△) 一套A+的网_垃圾分类网页设计目标怎么写

C# .Net 发布后,把dll全部放在一个文件夹中,让软件目录更整洁_.net dll 全局目录-程序员宅基地

文章浏览阅读614次,点赞7次,收藏11次。之前找到一个修改 exe 中 DLL地址 的方法, 不太好使,虽然能正确启动, 但无法改变 exe 的工作目录,这就影响了.Net 中很多获取 exe 执行目录来拼接的地址 ( 相对路径 ),比如 wwwroot 和 代码中相对目录还有一些复制到目录的普通文件 等等,它们的地址都会指向原来 exe 的目录, 而不是自定义的 “lib” 目录,根本原因就是没有修改 exe 的工作目录这次来搞一个启动程序,把 .net 的所有东西都放在一个文件夹,在文件夹同级的目录制作一个 exe._.net dll 全局目录

BRIEF特征点描述算法_breif description calculation 特征点-程序员宅基地

文章浏览阅读1.5k次。本文为转载,原博客地址:http://blog.csdn.net/hujingshuang/article/details/46910259简介 BRIEF是2010年的一篇名为《BRIEF:Binary Robust Independent Elementary Features》的文章中提出,BRIEF是对已检测到的特征点进行描述,它是一种二进制编码的描述子,摈弃了利用区域灰度..._breif description calculation 特征点

房屋租赁管理系统的设计和实现,SpringBoot计算机毕业设计论文_基于spring boot的房屋租赁系统论文-程序员宅基地

文章浏览阅读4.1k次,点赞21次,收藏79次。本文是《基于SpringBoot的房屋租赁管理系统》的配套原创说明文档,可以给应届毕业生提供格式撰写参考,也可以给开发类似系统的朋友们提供功能业务设计思路。_基于spring boot的房屋租赁系统论文