一、任务要求

利用MSP430F247单片机的P1和P4端口控制16个发光二极管D1~D16,发光二极管有8种花样显示,显示速度可调,由P2端口的三个按键控制,分别是模式按键、加速按键、减速按键。模式按键按下一次,花样显示模式变换一次,按下8次后循环到第一种模式,加速和减速按键可以控制LED的闪烁速度。

二、分析说明

按照任务要求,16个发光二极管可以组成更加丰富的花样变换,由于MSP430单片机的每个端口是8位,因此需要两个完整的端口来控制发光二极管,这还需要在程序中将16位的输出转换为两个8位的输出,此外,本实例还将介绍程序的模块化设计、函数指针数组等内容。

三、电路设计

16个花样灯控制的硬件电路如下图所示。值得注意的是,P1和P4端口在连接到LED时,是用的网络标号Q1~Q16来表示网络连接关系,这样就简化了图纸的连接,否则会导致图纸上连线过多过密,影响到图纸的简洁和美观。

四、程序代码

由于16个花样灯的功能较为复杂,将所有程序代码写在一个文件中不是一个好的程序设计习惯,此时一般采用模块化编程。

所谓模块化编程是指将一个较大的程序划分为若干功能独立的模块,对各模块进行独立开发,然后再将这些模块统一合并为一个完整的程序。这种方法是C语言中的面向过程的编程方法,可以缩短开发周期,提高程序的可读性和可维护性。

在单片机程序里,程序比较小或者功能比较简单的时候,我们不需要采用模块化编程,但是,当程序功能复杂、涉及的资源较多的时候,模块化编程就能体现它的优越性了。如前面写过的闪烁灯程序、流水灯程序和花样灯程序,每一个程序都是只用一个源文件编写就能完成,但程序较为复杂,涉及的功能比较多,将程序全部集中在一个源文件里,将导致主体程序臃肿且杂乱。这样做降低了程序的可读性、可维护性和代码的重用率。如果把这三个程序当做三个独立的模块放到主体程序中进行模块化编程,效果就不一样了。

实际上,模块化编程就是模块合并的过程,也是建立每个模块的头文件和源文件并将其加入到主体程序的过程。主体程序调用模块的函数是通过包含模块的头文件来实现的,模块的头文件和源文件是模块密不可分的的两个部分,缺一不可。所以,模块编编程必须提供每个模块的头文件和源文件。

下面以花样灯为例来介绍模块化编程。首先将16为花样灯的程序分解为三部分,分别是主函数、按键程序和LED显示程序。

1、建立模块的源文件

在模块化编程里,模块的源文件是实现该模块功能的变量定义和函数定义,不能定义main函数。建立模块源文件的方法很多,直接在主体程序里新建一个文件,把代码添加进去,保存为.c的文件,然后将该文件加入到主体程序;或者是在程序外建立一个记事本文件,把代码添加进去,保存为.c文件,然后把文件添加到主体程序里,在本实例中,把键盘处理代码放在key.c文件中。

程序如下。#include "msp430f247.h"

#include "stdlib.h"

#include "string.h"

#include "LedDisplay.h"

#include "key.h"

extern unsigned char RunMode;

extern unsigned char LEDDirection;

extern unsigned int SystemSpeed,SystemSpeedIndex;

extern unsigned char LEDFlag;

extern unsigned int LEDIndex;

unsigned int SpeedCode[]={1,2,3,5,8,10,14,17,20,30,

40,50,60,70,80,90,100,120,140,160,

180,200,300,400,500,600,700,800,900,1000};

unsigned char GetKey(void)

{

unsigned char KeyTemp;

unsigned char Key=0;

if((P2IN&0x07) != 0x07)

{

delayms(20);

if((P2IN&0x07) == 0x07)

return 0x00;

KeyTemp=P2IN&0x07;

if(KeyTemp == 0x06)

Key=0x01;

if(KeyTemp == 0x05)

Key=0x02;

if(KeyTemp == 0x03)

Key=0x03;

}

return Key;

}

void SetSpeed(unsigned char Speed)

{

SystemSpeed = SpeedCode[Speed];

}

void process_key(unsigned char Key)

{

if(Key&0x01)

{

LEDDirection=1;

LEDIndex=0;

LEDFlag=1;

RunMode=(RunMode+1)%8;

}

if(Key&0x02)

{

if(SystemSpeedIndex>0)

{

--SystemSpeedIndex;

SetSpeed(SystemSpeedIndex);

}

}

if(Key&0x03)

{

if(SystemSpeedIndex<28)

{

++SystemSpeedIndex;

SetSpeed(SystemSpeedIndex);

}

}

}

2、建立模块的头文件

模块的头文件就是模块和主体程序的接口,里面是模块源文件的函数声明。建立头文件的方法和建立源文件的方法类似,只是在保存的时候,把文件保存为.h格式的文件。本实例中,把键盘处理的源文件里的函数声明放到文件里并保存为key.h。每个模块的头文件最终都要被包含在主体程序里,而且不能重复包含,否则编译器报错。

程序如下。/*****************************************软件延时,主频1M*******************/

#define CPU_F1 ((double)1000000)

#define delay_us1M(x) __delay_cycles((long)(CPU_F1*(double)x/1000000.0))

#define delay_ms1M(x) __delay_cycles((long)(CPU_F1*(double)x/1000.0))

/****************************************************************************/

unsigned char GetKey(void);

void SetSpeed(unsigned char Speed);

void process_key(unsigned char key);

3、同理,建立LED显示控制的头文件如下void Mode_0(void);

void Mode_1(void);

void Mode_2(void);

void Mode_3(void);

void Mode_4(void);

void Mode_5(void);

void Mode_6(void);

void Mode_7(void);

void Mode_8(void);

void LedShow(unsigned int LedState);

void delayms(unsigned int t);

4、建立LED显示控制的C文件如下#include "msp430f247.h"

#include "stdlib.h"

#include "string.h"

#include "LedDisplay.h"

#include "key.h"

extern unsigned char RunMode;

extern unsigned char LEDDirection;

extern unsigned char LEDFlag;

extern unsigned int LEDIndex;

void (*run[8])(void)={Mode_0,Mode_1,Mode_2,Mode_3,

Mode_4,Mode_5,Mode_6,Mode_7};

void Mode_0(void)

{

LedShow(0x0001<

LEDIndex=(LEDIndex+1)%16;

}

void Mode_1(void)

{

LedShow(0x8000>>LEDIndex);

LEDIndex=(LEDIndex+1)%16;

}

void Mode_2(void)

{

if(LEDDirection) LedShow(0x0001<

else LedShow(0x8000>>LEDIndex);

if(LEDIndex==15) LEDDirection =! LEDDirection;

LEDIndex=(LEDIndex+1)%16;

}

void Mode_3(void)

{

if(LEDDirection)

LedShow(~(0x0001<

else

LedShow(~(0x8000>>LEDIndex));

if(LEDIndex==15)

LEDDirection =! LEDDirection;

LEDIndex=(LEDIndex+1)%16;

}

void Mode_4(void)

{

if(LEDDirection)

{

if(LEDFlag)

LedShow(0xfffe<

else

LedShow(~(0x7fff>>LEDIndex));

}

else

{

if(LEDFlag)

LedShow(0x7fff>>LEDIndex);

else

LedShow(~(0xfffe<

}

if(LEDIndex==15)

{

LEDDirection =! LEDDirection;

if(LEDDirection) LEDFlag =! LEDFlag;

}

LEDIndex=(LEDIndex+1)%16;

}

void Mode_5(void)

{

if(LEDDirection)

LedShow(0x000f<

else

LedShow(0xf000>>LEDIndex);

if(LEDIndex==15)

LEDDirection =! LEDDirection;

LEDIndex=(LEDIndex+1)%16;

}

void Mode_6(void)

{

if(LEDDirection)

LedShow(~(0x000f<

else

LedShow(~(0xf000>>LEDIndex));

if(LEDIndex==15)

LEDDirection =! LEDDirection;

LEDIndex=(LEDIndex+1)%16;

}

void Mode_7(void)

{

if(LEDDirection)

LedShow(0x003f<

else

LedShow(0xfc00>>LEDIndex);

if(LEDIndex==15)

LEDDirection =! LEDDirection;

LEDIndex=(LEDIndex+1)%16;

}

void Mode_8(void)

{

LedShow(++LEDIndex);

}

void LedShow(unsigned int LedState)

{

P1OUT=~(LedState&0x00ff);

P4OUT=~((LedState>>8)&0x00ff);

}

void delayms(unsigned int t)

{

unsigned int i;

while(t--)

{

for(i=1000;i>0;i--);

if((P2IN&0x07) != 0x07) break;

}

}

5、在主程序里包含模块的头文件,完成程序总体设计,把上面的key.h和LedDisplay.h分别添加到主程序头部,如下图所示,

主程序如下

五、程序说明

从主程序看,代码非常简洁,便与编程人员理解和修改,更重要的是键盘处理程序和显示控制程序可以重复适用于其它设计中。

特别要指出的是在显示控制程序中有一行代码。void (*run[8])(void)={Mode_0,Mode_1,Mode_2,Mode_3,

Mode_4,Mode_5,Mode_6,Mode_7};

这些代码定义了一个函数指针数组,将8个显示模式的函数地址保存在run数组中,该数组保存的是函数的指针,在主程序中用 run[RunMode]();进入不同的显示模式。RunMode为显示模式变量,可以通过模式按键修改

六、仿真结果与分析

装载程序后,即可点击运行按钮观察程序运行结果,并根据运行结果判断程序是否达到设计初衷。

单片机16个灯四种花样c语言,基于Proteus的MSP430单片机仿真实例5-16个花样灯控制...相关推荐

  1. c51中断优先级c语言,基于proteus的51单片机开发实例(14)中断嵌套和中断优先级...

    1. 基于proteus的51单片机开发实例(14)中断嵌套和中断优先级 1.1. 实验目的 在前面实例中我们已经学习了51单片机的定时器/计数器中断,外部中断,通过这些实例,知道了中断电路的设计,中 ...

  2. 51单片机有几个通用io口_51单片机IO口的四种使用方法

    原标题:51单片机IO口的四种使用方法 传统51单片机IO接口只可以作为标准双向IO接口,如果用其来驱动LED只能用灌电流的方式或是用三极管外扩驱动电路. 灌电流方式 LED正极接VCC,负极接IO口 ...

  3. c++程序设计_基于proteus的51单片机开发实例30-模块化程序设计

    1. 基于proteus的51单片机开发实例30-模块化程序设计 1.1. 实验目的 模块化程序设计 不知不觉我们的51单片机开发实例已经进行到第三十篇了,是时候进行一个总结和反思了,总结什么?反思什 ...

  4. hc05与单片机连接图_基于proteus的51单片机开发实例37-DAC0832

    学习手记 1. 基于proteus的51单片机开发实例37-DAC0832 1.1. 实验目的 之前我们学习了数模转换芯片DAC0808,今天我们继续学习另一种D/A转换芯片DAC0832. 1.2. ...

  5. hc05与单片机连接图_基于proteus的51单片机开发实例(13)-LED指示那个按键被按下

    1. 基于proteus的51单片机开发实例(13)-LED指示那个按键被按下 1.1. 实验目的 本实例将实现两路外部中断的检测和识别,让我们能够更好地理解51单片机的外部中断以及中断优先级的概念. ...

  6. 二叉树的存储结构及四种遍历(C语言)

    二叉树的存储结构: typedef struct TNode *Position; typedef Position BinTree; /* 二叉树类型 */ struct TNode{ /* 树结点 ...

  7. php封装webservice_四种php中webservice实现的简单架构方法及实例

    一:PHP本身的SOAP 所有的webservice都包括服务端(server)和客户端(client). 要使用php本身的soap首先要把该拓展安装好并且启用.下面看具体的code 首先这是服务端 ...

  8. ASP,php,jsp,ASP.net四种web平台语言的区别与前景

    ASP,PHP,JSP,ASP.NET 这是当前比较流行的四种WEB网站编程语言 现在做网站大部分都是使用这几种语言中的其一 ASP是基于WINDOWS平台的,简单易用,由于是运行在WINDOWS平台 ...

  9. 基于at89c51单片机的led数字倒计时器设计c语言,基于AT89C51单片机的LED数字倒计时器设计1.docx...

    基于AT89C51单片机的LED数字倒计时器设计1 单片机原理及其应用课程设计课 题: 基于AT89C51单片机的LED数字倒计时器设计专 业: 电工程及其自动化班 级: 2013 级 4班学 号: ...

最新文章

  1. 你应该知道的那些Android小经验
  2. 端计算(2)-android studio 的sdk,avd,grade及其它缓存配置
  3. pytorch:ResNet50做新冠肺炎CT照片是否确诊分类
  4. 魅族 C++ 微服务框架技术内幕揭秘
  5. jsp里加java代码,利用静态内部类为您的代码添加辅助功能-JSP教程,Java技巧及代码...
  6. C#.net实现密码加密算法的语句
  7. 系统集成管理师2011下半年软考透解 四
  8. [转载] 用python写的一个简单的记事本
  9. sql 将某一列的值拼接成字符串
  10. 19c(19.3) 单机数据库安装
  11. 总体参数的假设检验 R
  12. 【RDMA】基于RoCE的应用程序的MTU注意事项|探测网络中的MTU设置
  13. 在linux中运行安卓程序
  14. echarts网络拓扑图动态流程图
  15. Python高并发爬虫测评(2): 多进程, 多线程和异步协程哪个快?
  16. MySQL-8.0 RESTART命令远程重启mysqld
  17. 计算机组成原理常见题(四)
  18. js 倒计时算法及定时器的应用
  19. 81.一名【合格】前端工程师的自检清单
  20. 2022-2027年中国煤制尿素行业市场全景评估及发展战略规划报告

热门文章

  1. 西游记中孙悟空的蜕变
  2. hadoop(hdfs)常见面试题
  3. 逻辑回归三部曲——逻辑回归项目实战(信贷数据+Python代码实现)
  4. 【优化覆盖】基于matlab粒子群算法优化无人机编队布局求解车载网络通信覆盖优化问题【含Matlab源码 2021期】
  5. 文件上传漏洞绕过手法
  6. windows10 安装 cuda8.0 cudnn6.0 tensorflow-gpu1.3.0 pycharm jupyter 及路径
  7. OPC通讯开发——客户端开发工具WTopcclient说明手册部分翻译及个人补充
  8. arrive at/agree with/account for等动词词组
  9. 计算机乡村少年宫教案,乡村少年宫电脑绘画兴趣小组教案
  10. 合宙ESP32S3 CameraWebServe 测试demo