《单片机开发进阶》(基于STC8A8K64D4的炫彩灯光的设计与实现)

声明:本项目采用STC8A8K64D4作为开发芯片与传统51单片机相比,STC8A8K64D4在性能和功能上有显著提升。STC8A8K64D4具有更高的处理速度、更大的存储容量以及更多的外设资源,使其在复杂应用场景中的表现更加出色。此外,STC8A8K64D4还支持多种通信接口,如I2C、SPI和UART,方便与其他设备进行数据交换。这些优势使得STC8A8K64D4在开发嵌入式系统和实现高级算法时具有明显的优势。

在嵌入式项目中要有纵览全局的眼光。对于各个模块心理都要有准确的认识。代码格式也有严格规范,满足模块化要求,使代码可以复用。

 1  引言     

                                                   

1.1 课题背景

炫彩灯光在现代社会中得到了广泛的应用,不仅用于娱乐场所、演出、节日庆典等场合,还在室内和室外的装饰中扮演着重要的角色。随着科技的不断发展,人们对灯光效果的要求也越来越高。为了实现更加个性化、多样化的灯光效果,设计一个灵活、智能的炫彩灯光系统具有重要的意义。

为了满足不同场景的需求,设计一种基于STC8A8K64D4微控制器的炫彩灯光系统具有重要意义。STC8A8K64D4是一款高性能、低功耗的单片机,具有丰富的外设接口和强大的计算能力,非常适合用于控制炫彩灯光。

1.2国内外研究现状

1.2.1国外研究现状

国内外的研究者在硬件设计方面,广泛使用各种微控制器和外围电路,如Arduino、Raspberry Pi等。它们提供了丰富的IO接口和灵活的控制能力,可用于控制不同类型的灯光效果。此外,PWM技术被广泛应用于调整灯光的亮度和颜色。

在灯光效果设计方面,研究者采用了多种算法和技术,如颜色混合算法、颜色空间转换算法、亮度调节算法等,以实现各种炫彩灯光效果。此外,一些研究还探索了音乐节拍分析和声音识别等技术,将灯光与音效进行同步控制。

总体而言,国外关于基于微控制器的炫彩灯光系统的研究较为活跃。已有的研究成果涵盖了硬件设计、灯光效果控制算法、用户界面设计和系统可靠性等多个方面。然而,仍有机会进行进一步的研究和创新,特别是在灯光效果的个性化调整、系统优化和用户体验方面。

1.2.2国内研究现状

国内的研究者在炫彩灯光系统的硬件设计方面,常使用各类微控制器,如51系列单片机、STM32系列微控制器等。通过选用适当的外围电路和传感器,能够实现对灯光的控制和感应。同时,还进行了一些相关的硬件开发,如PWM控制电路、灯光驱动电路等。

国内研究者致力于设计多样化的灯光效果和控制算法。研究中涉及的算法包括颜色混合算法、渐变算法、闪烁算法等。此外,一些研究还探索了光线跟随、光影变化等特殊效果的设计与实现。

为了方便用户操作,国内研究者开发了各种用户界面和交互方式。一些研究采用了触摸屏、无线遥控器等交互工具,通过图形界面实现对灯光效果的调节。还有研究使用手机APP进行远程控制,提供更加便捷的操作方式。国内的研究主要应用于娱乐场所、舞台演出、建筑装饰、城市照明等领域。例如,在演唱会、晚会等大型活动中,基于微控制器的炫彩灯光系统被广泛应用,为现场观众带来视听盛宴。

总体而言,国内的研究者在基于微控制器的炫彩灯光系统方面取得了一定的研究成果。然而,还有许多方面有待进一步研究,如系统的智能化、能耗优化、与音效的联动等。未来的研究可以进一步推动国内炫彩灯光系统的发展与创新。

 2  总体设计     

                                                   

2.1 系统功能

基于STC8A8K64D4微控制器的炫彩灯光的设计旨在实现以下主要功能:

声音测量功能:通过连接麦克风音量传感器和AD转换器,用来接收声波,对噪声的强度进行测量。该传感器有一个模拟量和数字量输出,模拟量是一个在一定范围内变化的连续数值,将其输入到STC8A8K64D4,利用A/D转换进行测量、判断,并通过AD转换器将模拟电压信号转换为数字信号,以便微控制器进行处理。作用相当于一个麦克风。

灯光效果控制:系统应具备丰富的灯光效果控制功能,包括颜色变换、亮度调节、闪烁、渐变等。用户可以通过独立按键选择不同的效果,实时控制灯光的变化。

参数调节:用户可以通过独立按键对灯光的参数进行调节,包括颜色、亮度、速度等。系统应提供直观的界面和操作方式,使用户能够方便地调整参数并实时查看效果。

多设备联动:系统支持多个灯光设备的联动,可以同时控制多个设备的灯光效果,实现统一的视觉效果。

系统稳定性和可靠性:系统应具备良好的稳定性和可靠性,能够长时间稳定运行。同时,应考虑故障处理等机制,以确保系统的正常运行和保护设备的安全。

以上功能是基于STC8A8K64D4微控制器的炫彩灯光系统设计的主要目标和功能。能够提供丰富的灯光效果和灵活的控制方式,满足用户对炫彩灯光的多样化需求。根据具体需求和应用场景,可以进行相应的定制和扩展。

2.2 系统环境搭建

2.2.1软件环境搭建(使用Keil 5)

下载和安装Keil 5:访问Keil官方网站,下载适用于您的操作系统的Keil 5集成开发环境(IDE)。

配置Keil 5:打开Keil 5 IDE,并根据提示进行安装和配置。配置包括选择合适的MCU型号(STC8A8K64D4)、设置编译器和调试器等。

创建新工程:在Keil 5 IDE中创建一个新的工程。选择STC8A8K64D4作为目标MCU,并指定工程文件的存储位置。

导入库文件:根据需要,导入STC8系列的库文件。这些库文件包含STC8A8K64D4的相关驱动和函数,可简化开发过程。

编写代码:在Keil 5 IDE中编写代码。根据系统功能的需求,编写初始化代码、声音测量算法、数据显示和更新代码、用户交互代码等。

编译和烧录:使用Keil 5 IDE提供的编译器,编译源代码。然后,将生成的可执行文件通过烧录器或调试器,将程序烧录到STC8A8K64D4微控制器芯片中。

调试和测试:连接电源和相关外设,使用调试工具或编写测试代码,炫彩灯光系统的功能和准确性。进行实际环境测量和显示测试,并校准测量结果。

通过以上的硬件环境搭建和软件环境搭建步骤,您可以建立基于STC8A8K64D4微控制器的炫彩灯光系统的开发环境,并进行系统的开发、调试和测试工作。

2.2.2硬件环境搭建

硬件连接:将STC8A8K64D4微控制器与其他硬件模块进行连接。连接麦克风音量传感器到合适的引脚,并连接AD转换器和LED1602显示模块。根据硬件设计要求,进行正确的连线和引脚分配。

调试工具准备:准备适用于STC8A8K64D4的调试工具,如USB转串口模块或调试器。这些工具用于与微控制器进行通信、烧录程序和调试代码。

外部组件连接:根据具体需求,连接外部组件,如按键、蜂鸣器。确保这些组件与微控制器正确连接,并按照设计要求进行连线。

硬件调试:在完成硬件连接后,进行硬件调试。通过使用示波器、万用表和逻辑分析仪等工具,检查电路的连通性、电压水平和信号波形。确保所有硬件模块正确工作,并消除任何硬件故障或连接问题。

硬件环境搭建是基于STC8A8K64D4微控制器的炫彩灯光系统设计过程中不可或缺的一步。正确连接和配置硬件模块将为系统功能的实现奠定基础,并确保炫彩灯光系统能够准确测量、显示和处理声音数据。

2.3 设计的总体框图

2.4 硬件描述

2.4.1 STC8A8K64D4微控制器

STC8A8K64D4微控制器是基于8051内核的高性能单片机。它具有64KB的Flash存储器和8KB的RAM,可以满足炫彩灯光系统的存储和处理需求。该微控制器还提供了丰富的GPIO引脚,用于与其他硬件模块的连接和通信。

2.4.2 A/D 模数转换

A/D 模数转换是将外部的模拟电压转换为 数字信号后,供单片机进行处理,以便单片机能“感知”到外部“消息”。

模拟信号,在电子电路中,通常根据信号值域是否随时域连续变化的特征箱关得号区分为模拟信号和数字信号。如图 1-1 所示,模拟信号是一种数值在时域上值域连续变化的信号。从电学角度去看,这种信号的幅度和相位是连续变化的,所以很多文献上也将其称为“连续信号”。熟悉的正弦波信号、声音信号、压力信号、手机天线部分的电磁信号等都属于模拟信号,很多传感器输出的 4~20mA 电流信号、0~5V 电压信号、0~10V 电压信号,图 1-1 模拟信号数值变化曲线也都是模拟信号。

图1-1 模拟信号数值变化曲线

通常把这种物理量称为“模拟量”,表示模拟量的电信号称为“模拟电信号”,工作运行在这种信号下的电子电路称为“模拟电子电路”。

数字信号,在单片机信号处理中,大多都是数字信号,也就是我们通常所说的高低电平信号。如图 1-2所示,数字信号是一种数值在时域上离散变化的信号,例如数字脉冲信号。

图1-2 数字信号数值分布特征

2.4.3 麦克风音量传感器

选择麦克风音量传感器,如图 1-3 所示,并将其连接到开发板上的模拟输入通道。确保正确连接传感器的引脚,通常麦克风音量传感器具有四个引脚,VCC是供电接口,可接3.3V、5V。GND接地。SIG用于模拟信号输出。NC空接口,不需要连接。

图1-3 麦克风音量传感器参数图

2.4.4 LED1602液晶显示模块

LED1602液晶显示模块是一种常用的字符显示模块,由16列2行的字符组成。它采用液晶显示技术,具有低功耗、高可靠性和清晰可见的特点。在基于STC8A8K64D4的炫彩灯光系统设计中,LED1602显示模块被用于将声音数据以可视化的方式显示出来。

LED1602显示模块的硬件连接相对简单,一般包括以下几个主要部分:

LCD控制器:LED1602显示模块内部包含一个LCD控制器,用于控制字符的显示、光线的背光和其他相关功能。在STC8A8K64D4炫彩灯光系统设计中,通过与LCD控制器进行通信,可以向显示模块发送指令和数据,控制显示内容和显示状态。

字符存储区:LED1602显示模块具有16列2行的字符存储区,用于显示字符和符号。每个字符存储区可以显示一个ASCII字符,包括数字、字母、符号和自定义字符。通过与STC8A8K64D4微控制器进行通信,可以将声音数据转换为相应的字符,并将其发送到LED1602显示模块的字符存储区。

背光控制:LED1602显示模块还具有背光控制功能,可以控制显示的背光亮度。一般情况下,通过STC8A8K64D4微控制器的GPIO引脚连接到LED1602显示模块的背光控制引脚,以实现背光的开启和关闭。这样可以根据需要调整背光亮度,提供良好的可视性。

电源供应:LED1602显示模块需要电源供应,一般为5V电源。在设计中,需要将模块的电源引脚与适当的电源连接,以确保模块正常工作。

2.5 软件描述(寄存器配置)

端口配置:

/*-------------------------------------------------------------------

/*      (C) Copyright 2021-2022, nbufe. All Rights Reserved

/*-------------------------------------------------------------------

/* File name   : STC8Ax_Init.c

/* Description :

/* Author      : nbufe

/*-------------------------------------------------------------------

/* Update note:

/* ---------   -----------   ----------------------------------------

/*   Date        Author                       Note

/* ---------   -----------   ----------------------------------------

/*

**/

/* 包含头文件 -------------------------------------------------------*/

#include "STC8Ax_INIT.h"

/* 私有类型定义 -----------------------------------------------------*/

/* None. */

/* 私有宏定义 -------------------------------------------------------*/

/* None. */

/* 私有变量 ---------------------------------------------------------*/

/* None. */

/* 扩展变量 ---------------------------------------------------------*/

/* None. */

/* 私有函数原形 -----------------------------------------------------*/

/* None. */

/* 函数体 -----------------------------------------------------------*/

/* None. */

/* 第一区 初始化单片机 */

/**

 * 功能:初始化单片机

 * 参数:None

 * 返回:None

 * 说明:

 */

void System_Init()

{

    GPIO_Init(GPIO_P0, Pin_All, GPIO_MODE_OUT_PP);

    GPIO_Init(GPIO_P1, Pin_All, GPIO_MODE_IN_FLOATING );

    GPIO_Init(GPIO_P1, Pin_2 ,  GPIO_MODE_OUT_PP);

    GPIO_Init(GPIO_P2, Pin_All, GPIO_MODE_WEAK_PULL );

    GPIO_Init(GPIO_P2, Pin_0, GPIO_MODE_OUT_PP);

    GPIO_Init(GPIO_P3, Pin_All, GPIO_MODE_WEAK_PULL );

    GPIO_Init(GPIO_P4, Pin_All, GPIO_MODE_WEAK_PULL );

    GPIO_Init(GPIO_P7, Pin_All, GPIO_MODE_WEAK_PULL );



    Peripheral_Init();

    Time0_Config();

    Timer1_Init();

    ADC_Init();

    LCD1602_Init(); // 初始化LCD显示屏

    

    led_dr1 = 1; //LED灭

    led_dr2 = 1; //LED灭

    led_dr3 = 1; //LED灭

    led_dr4 = 1; //LED灭

    led_dr5 = 1; //LED灭

    led_dr6 = 1; //LED灭

    led_dr7 = 1; //LED灭

    led_dr8 = 1; //LED灭

    led_dr9 = 1; //LED灭

}

void Timer1_Init(void) //1毫秒@24.000MHz

{

    AUXR |= 0x40;        //定时器时钟1T模式

    TMOD &= 0x0F;        //设置定时器模式

    TL1 = 0x40;        //设置定时初始值

    TH1 = 0xA2;        //设置定时初始值

    TF1 = 0;            //清除TF1标志

    TR1 = 1;            //定时器1开始计时

    ET1 = 1;            //使能定时器1中断

}

/**

* 功能:初始化外围设备

 * 参数:None

 * 返回:None

 * 说明:

 */

void Time0_Config() //初始化外围

{

    AUXR &= 0x7F;    //定时器时钟12T模式

    TMOD &= 0xF0;    //设置定时器模式



    TL0 = 0x30;        //设置定时初始值    //1毫秒@24.000MHz初值

    TH0 = 0xF8;        //设置定时初始值



    TF0 = 0;        //清除TF0标志

    TR0 = 1;        //定时器0开始计时

}



/* 第二区 初始化外围 */

/**

 * 功能:初始化外围设备

 * 参数:None

 * 返回:None

 * 说明:

 */

void Peripheral_Init() //初始化外围

{

    EA = 1;       //开总中断

    TR0 = 1;      //启动定时中断

    ET0 = 1;

    TR1 = 1;    //定时器1开始计时

    ET1 = 1;    //使能定时器1中断

}



/*>>>>>>>>>> (C) COPYRIGHT NBUFE <<<<<< >>>>>> END OF FILE <<<<<<<<<<*/



定时器配置:

/*-------------------------------------------------------------------

/*      (C) Copyright 2021-2022, nbufe. All Rights Reserved

/*-------------------------------------------------------------------

/* File name   : STC8Ax_ISR.c

/* Description :

/* Author      : nbufe

/*-------------------------------------------------------------------

/* Update note:

/* ---------   -----------   ----------------------------------------

/*   Date        Author                       Note

/* ---------   -----------   ----------------------------------------

/*  

**/

/* 包含头文件 -------------------------------------------------------*/

#include "STC8Ax_ISR.h"



/* 私有类型定义 -----------------------------------------------------*/

/* None. */

/* 私有宏定义 -------------------------------------------------------*/

/* None. */

/* 私有变量 ---------------------------------------------------------*/

/* None. */

/* 扩展变量 ---------------------------------------------------------*/

/* None. */

/* 私有函数原形 -----------------------------------------------------*/

/* None. */

/* 函数体 -----------------------------------------------------------*/

/* 第四区 系统中断处理 */

/**

 * 功能:定时中断函数

 * 参数:None

 * 返回:None

 * 说明:

 */

void Time0_ISR() interrupt 1

{

    TF0 = 0;

    TR0 = 0;

    breathe();



    TH0 = 0xfe; //重装初始值(65535-500)=65035=0xfe0b

    TL0 = 0x0b;

    TR0 = 1;

}

void Timer1_Isr() interrupt 3

{

    TF1 = 0;

    TR1 = 0;

    Key_Scan();

    TL1 = 0x40;        //设置定时初始值    A240=41536

    TH1 = 0xA2;        //设置定时初始值

    TR1 = 1;        //定时器1开始计时

}



/*>>>>>>>>>> (C) COPYRIGHT NBUFE <<<<<< >>>>>> END OF FILE <<<<<<<<<<*/ 

ADC 特殊功能寄存器:

/*------------------------------------------------------------------*/

/* ADC 特殊功能寄存器*/

/*------------------------------------------------------------------*/

sfr ADC_CONTR   =    0xBC; //0000,0000 A/D转换控制寄存器

#define ADC_POWER 0x80 //bit7

#define ADC_START 0x40 //bit6

#define ADC_FLAG   0x20 //bit5

sfr ADC_RES     =    0xBD; //0000,0000 A/D转换结果高8位

sfr ADC_RESL    =    0xBE; //0000,0000 A/D转换结果低2位

 3  详细设计     

                                                   

3.1 主函数设计

3.1.1包含头文件

包含头文件:代码开始处包含了一些自定义的头文件和外部库文件,用于引入所需的函数和定义。这些头文件包括:

"main.h":主头文件,包含了所有其他头文件的引用。

"STC8Ax_INIT.h":STC8系列单片机初始化相关的头文件。

"STC8Ax_DELAY.h":STC8系列单片机延时函数相关的头文件。

".\LCD1602\LCD1602.h":LCD1602液晶显示屏相关的头文件。

".\ADC\ADC.h":ADC模块相关的头文件。

".\LED\LED.h":LED模块相关的头文件。

".\keyScan\keyScan.h" keyScan模块相关的头文件。

3.1.2主函数(main)流程

1.执行System_Init()函数:这个函数用于进行系统初始化,例如时钟设置、IO口配置等。

2.延迟500毫秒(Delay_ms(500)):通过Delay_ms()函数实现延时功能。

3.执行Peripheral_Init()函数:这个函数用于进行外设初始化,包括定时器、中断、串口等外设的初始化。

3.在LCD1602上显示字符串 " Sound ":使用LCD1602_ShowString()函数在LCD1602显示屏上显示字符串。

4.进入无限循环(while(1)):

5.执行key_service()函数:这个函数处理按键服务的应用程序,按键状态检测。

6.执行ADC_USE()函数:这个函数处理AD的应用程序,包括读取AD值、转换为实际参数等。

7.延迟500毫秒(Delay_ms(500)):通过Delay_ms()函数实现延时功能。

3.1.3主函数(main)详细代码
/*-------------------------------------------------------------------

/*      (C) Copyright 2022-2023, nbufe. All Rights Reserved

/*-------------------------------------------------------------------

/* File name   : main.c

/* Description :

/* Author      : nbufe

/*-------------------------------------------------------------------

/* Update note:

/* ---------   -----------   ----------------------------------------

/*   Date        Author                       Note

/* ---------   -----------   ----------------------------------------

/*

**/

/* 包含头文件 -------------------------------------------------------*/

#include  "main.h"



/* 私有类型定义 -----------------------------------------------------*/

/* None. */

/* 私有宏定义 -------------------------------------------------------*/

/* None. */

/* 私有变量 ---------------------------------------------------------*/

/* None. */

/* 扩展变量 ---------------------------------------------------------*/

/* None. */

/* 私有函数原形 -----------------------------------------------------*/

/* None. */

/* 函数体 -----------------------------------------------------------*/

/*

 * 功能: 主函数

 * 参数: None

 * 返回: None

 * 说明: None

 */

void main()

{

    System_Init();

    Delay_ms(500);

    Peripheral_Init();

    LCD1602_ShowString(1,0,"Sound");

    while(1)

    {

        key_service(); //按键服务的应用程序

        ADC_USE();

        Delay_ms(500);

    }

}



/*>>>>>>>>>> (C) COPYRIGHT NBUFE <<<<<< >>>>>> END OF FILE <<<<<<<<<<*/

3.2 AD转换模块的设计与实现

3.2.1包含头文件及其他参数

头文件:代码开始处包含了自定义的头文件"ADC.h",用于引入所需的函数和定义。

私有类型定义:使用了extern关键字声明了一个unsigned char类型的全局变量k。

私有变量:定义了一个私有变量:

unsigned int sum: 用于保存ADC转换结果的16位值(和)(高8位在ADC_RES,低8位在ADC_RESL)。

3.2.2 AD数模转换函数体流程

1.ADC_Init()函数:用于进行ADC的初始化。

清零ADC_RES和ADC_RESL寄存器。

配置P_SW2寄存器,选择ADC内部时序。

配置ADCTIM寄存器,设置ADC的内部时序。

清除P_SW2寄存器的相应位,选择系统时钟/2/16作为ADC时钟。

设置ADC_CONTR寄存器的最高位,使能ADC模块。

2.ADC_USE()函数:用于执行ADC的转换和相关操作。

设置ADC_CONTR寄存器的第6位,开始进行ADC转换。

空操作_nop_(),增加一定的延时。

检查ADC_CONTR寄存器的第5位,等待ADC转换完成。

清除ADC_CONTR寄存器的第5位,将ADC_FLAG标志位清零。

设置ADCCFG寄存器为0,选择左对齐方式(通常采用右对齐方式)。

将ADC_RES左移4位,将ADC_RESL右移4位,将两者合并为一个16位的数值sum。

在LCD显示器上显示变量 sum 的数值。

如果 sum 大于1500,执行以下操作:

增加变量 k 的值。

如果 k 的值大于等于8,将 k 的值重置为0。

根据 k 的值,设置P0口的输出,将对应的位取反。用来实现灯光的快速变化。

3.2.3 AD数模转换详细代码
/*-------------------------------------------------------------------

/*      (C) Copyright 2021-2022, nbufe. All Rights Reserved

/*-------------------------------------------------------------------

/* File name   : ADC.c

/* Description :

/* Author      : nbufe

/*-------------------------------------------------------------------

/* Update note:

/* ---------   -----------   ----------------------------------------

/*   Date        Author                       Note

/* ---------   -----------   ----------------------------------------

/*

**/

/* 包含头文件 -------------------------------------------------------*/

#include "ADC.h"



/* 私有类型定义 -----------------------------------------------------*/

extern unsigned char k;



/* 私有宏定义 -------------------------------------------------------*/

/* None. */

/* 私有变量 ---------------------------------------------------------*/

unsigned int sum = 0;



/* 扩展变量 ---------------------------------------------------------*/

/* None. */

/* 私有函数原形 -----------------------------------------------------*/

/* None. */

/* 函数体 -----------------------------------------------------------*/

/*

 * 功能: ADC初始化

 * 参数: None

 * 返回: None

 * 说明: None

 */

 void ADC_Init()

{

    ADC_RES = 0;

    ADC_RESL = 0;

    P_SW2 |= 0x80;

    ADCTIM = 0x0f;    //设置 ADC 内部时序

    P_SW2 &= 0x7f;

    ADCCFG = 0x0f;    //设置 ADC 时钟为系统时钟/2/16

    ADC_CONTR |= 0x80;    //使能 ADC 模块

}

/*

 * 功能: AD转化

 * 参数: None

 * 返回: None

 * 说明: None

 */

void ADC_USE()

{

    ADC_CONTR |= 0x40;

    _nop_();

    _nop_();

    while(!(ADC_CONTR & 0x20));

    ADC_CONTR &= ~0x20;               //ADC_FLAG清零

    ADCCFG = 0;                       //采用左对齐的方式(一般来说都采用右对齐

    sum = ADC_RES<<4;               //高八位赋值

sum|= ADC_RESL>>4



    LCD_ShowNum(1, 1, sum, 5);

    if(sum>1500)

    {

        k++;

        if(k>=8)k=0;

        P0=~(0x01<<k);

    }

}

/*>>>>>>>>>> (C) COPYRIGHT NBUFE <<<<<< >>>>>> END OF FILE <<<<<<<<<<*/

3.3 LED1602模块的设计与实现

3.3.1包含头文件及其他参数

头文件:如"STC8Ax_GPIO.h"、"STC8Ax_REG.h"和"STC8Ax_DELAY.h"

定义LCD1602控制引脚(RS、RW、EN)和数据总线(DB)的硬件端口连接。

3.3.2 LED1602函数体流程

实现函数 `LCD1602_ReadBusy()`,用于检查LCD的忙标志。它会等待忙标志(位7)被清除,表示LCD已准备好接受命令或数据。

实现函数 `LCD1602_Clear()`,向LCD发送清除显示的命令(0x01)。

实现函数 `LCD1602_WriteCmd()`,用于向LCD写入命令。它首先调用 `LCD1602_ReadBusy()` 来确保LCD不忙,将RS(寄存器选择)引脚设置为0(表示命令),将RW(读/写)引脚设置为0(表示写操作),将命令写入数据总线,切换EN(使能)引脚以锁存命令,然后返回。

实现函数 `LCD1602_WriteData()`,用于向LCD写入数据。它的过程与 `LCD1602_WriteCmd()` 类似,但将RS引脚设置为1(表示数据),并将数据写入数据总线。

实现函数 `LCD_run()`,用于控制显示的滚动行为。它接受一个参数 `flag`,用于指定滚动方向:0 表示不滚动,1 表示左移,2 表示右移。该函数向LCD发送相应的命令(0x06、0x18 或 0x1C)。

实现函数 `LCD1602_SetCursor()`,用于在LCD上设置光标位置。它根据给定的x和y坐标计算地址,并向LCD发送相应的命令。

实现函数 `LCD1602_DisplayChar()`,用于在LCD的指定位置(x、y)显示一个字符。它根据坐标计算地址,并向LCD发送命令和数据。

实现函数 `LCD1602_ShowString()`,用于在LCD的指定位置(x、y)显示一个字符串。它调用 `LCD1602_SetCursor()` 来设置光标位置,然后将字符串的每个字符写入LCD。

实现函数 `LCD1602_Init()`,用于初始化LCD。它等待15毫秒的延迟,向LCD发送初始化序列(0x38、0x38、0x38),设置显示模式(0x0C),设置光标移动方向(0x06),并清除显示。

实现函数 `LCD_Pow()`,用于计算一个数的幂。它接受两个参数(X和Y),并返回X的Y次方的值。

实现函数 `LCD_ShowNum()`,用于在LCD的指定位置(行、列)显示一个数字。它计算数字的位数,并使用 `LCD1602_WriteData()` 显示每个位上的数字。

3.3.3 LED1602函数体详细代码

/*-------------------------------------------------------------------

/*      (C) Copyright 2021-2022, nbufe. All Rights Reserved

/*-------------------------------------------------------------------

/* File name   : LCD1602.c

/* Description :

/* Author      : nbufe

/*-------------------------------------------------------------------

/* Update note:

/* ---------   -----------   ----------------------------------------

/*   Date        Author                       Note

/* ---------   -----------   ----------------------------------------

/*

**/

/* 包含头文件 -------------------------------------------------------*/

#include"lcd1602.h"

/* 私有类型定义 -----------------------------------------------------*/

/* None. */

/* 私有宏定义 -------------------------------------------------------*/

/* None. */

/* 私有变量 ---------------------------------------------------------*/

/* None. */

/* 扩展变量 ---------------------------------------------------------*/

/* None. */

/* 私有函数原形 -----------------------------------------------------*/

void LCD1602_Init();   //1602初始化

void LCD1602_ReadBusy();

void LCD1602_Clear();

void LCD1602_WriteCmd(uint8_t cmd);

void LCD1602_WriteData(uint8_t dat);

void LCD1602_SetCursor(uint8_t x, uint8_t y);

/* 函数体 -----------------------------------------------------------*/

/*

/*

 * 功能: LCD1602 忙检测函数

 * 参数: None

 * 返回: None

 * 说明: 判断bit7是0,允许执行;1禁止

 */

void LCD1602_ReadBusy()

{

    uint8_t sta;

    LCD1602_DB = 0xff;

    LCD1602_RS = 0;

    LCD1602_RW = 1;

    do

    {

        LCD1602_EN = 1;

        sta = LCD1602_DB;

        LCD1602_EN = 0;         //使能,用完就拉低,释放总线

    }

    while(sta & 0x80);

}

/**

 * @brief: LED1602清屏程序

 * @param: None

 * @return: None

 * @note: None

 */

void LCD1602_Clear()

{

    LCD1602_WriteCmd(0x01);

}

/*

 * 功能: LCD1602 写命令函数

 * 参数: None

 * 返回: None

 * 说明: None

 */

/*void LCD1602_WriteCmd(uint8_t cmd)

{

    LCD1602_ReadBusy();

    LCD1602_RS = 0;

    LCD1602_RW = 0;

    LCD1602_DB = cmd;

    LCD1602_EN = 1;

    LCD1602_EN = 0;

} */

void LCD1602_WriteCmd(uint8_t cmd)

{

    LCD1602_ReadBusy();

    LCD1602_RS = 0;

    LCD1602_RW = 0;

    LCD1602_DB = cmd;

    Delay_ms(2);

    LCD1602_EN = 1;

    Delay_ms(2);

    LCD1602_EN = 0;

}

/*

 * 功能: LCD1602 写数据函数

 * 参数: None

 * 返回: None

 * 说明: None

 */

void LCD1602_WriteData(uint8_t dat)

{

    LCD1602_ReadBusy();

    LCD1602_RS = 1;

    LCD1602_RW = 0;

    LCD1602_EN = 1;

    Delay_ms(2);

    LCD1602_DB = dat;

    Delay_ms(2);

    LCD1602_EN = 0;

}

/**

 * @brief: LCD1602滚动显示函数

 * @param: flag

 * @return: None

 * @note: 输入0不滚动屏幕,输入1左移,输入2右移

 */

void LCD_run(uint8 flag)

{

    switch (flag)

    {

    case 0:

        LCD1602_WriteCmd(0x06);

        break;

    case 1:

        LCD1602_WriteCmd(0x18);

        break;

    case 2:

        LCD1602_WriteCmd(0x1C);

        break;

    default:

        break;

    }

}

/*

 * 功能: LCD1602 坐标显示函数

 * 参数: None

 * 返回: None

 * 说明: None

 */

void LCD1602_SetCursor(uint8_t x, uint8_t y)

{

    uint8_t addr;

    if(y == 0)

        addr = 0x00 + x;

    else

        addr = 0x40 + x;

    LCD1602_WriteCmd(addr | 0x80);

}

/*

 * 功能: LCD1602 按指定位置显示一个字符函数

 * 参数: None

 * 返回: None

 * 说明: None

 */

void LCD1602_DisplayChar(uint8_t x, uint8_t y, uint8_t dat)

{

    y &= 0x1;

    x &= 0xF;                        //限制x不能大于15,y不能大于1

    if (y) x |= 0x40;                //当要显示第二行时地址码+0x40;

    x |= 0x80;                       //算出指令码

    LCD1602_WriteCmd(x);             //发命令字

    LCD1602_WriteData(dat);          //发数据

}

/*

 * 功能: LCD1602 显示字符串函数

 * 参数: None

 * 返回: None

 * 说明: None

 */

void LCD1602_ShowString(uint8_t x, uint8_t y, uint8_t *str)

{

    LCD1602_SetCursor(x, y);            //当前字符的坐标

    while(*str != '\0')

    {

        LCD1602_WriteData(*str++);

    }

}

/*

 * 功能: LCD1602 初始化函数

 * 参数: None

 * 返回: None

 * 说明: None

 */

void LCD1602_Init()

{

    Delay_ms(15);

    LCD1602_WriteCmd(0x38);

    Delay_ms(5);

    LCD1602_WriteCmd(0x38);

    Delay_ms(5);

    LCD1602_WriteCmd(0x38); // 设置显示模式

    LCD1602_WriteCmd(0x0C); // 开显示,显示光标,光标不闪烁

    LCD1602_WriteCmd(0x06); // 光标右移,屏幕不移动

    LCD1602_Clear();        // 清屏

}

/**

/*

 * 功能: 返回值=X的Y次方

 * 参数: None

 * 返回: None

 * 说明: None

 */

int LCD_Pow(int X,int Y)

{

    unsigned char i;

    int Result=1;

    for(i=0;i<Y;i++)

    {

        Result*=X;

    }

    return Result;

}

/*

 * 功能: LCD1602 显示数字

 * 参数: None

 * 返回: None

 * 说明: None

 */

void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)

{

    unsigned char i;

    LCD1602_SetCursor(Line,Column);

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

    {

        LCD1602_WriteData(Number/LCD_Pow(10,i-1)%10+'0');

    }

}

/*-------------------------------------------------------------------

/*      (C) Copyright 2021-2022, nbufe. All Rights Reserved

/*-------------------------------------------------------------------

/* File name   : LCD1602.c

/* Description :

/* Author      : nbufe

/*-------------------------------------------------------------------

/* Update note:

/* ---------   -----------   ----------------------------------------

/*   Date        Author                       Note

/* ---------   -----------   ----------------------------------------

/*

**/

/* 包含头文件 -------------------------------------------------------*/

#include"lcd1602.h"



/* 私有类型定义 -----------------------------------------------------*/

/* None. */

/* 私有宏定义 -------------------------------------------------------*/

/* None. */

/* 私有变量 ---------------------------------------------------------*/

/* None. */

/* 扩展变量 ---------------------------------------------------------*/

/* None. */



/* 私有函数原形 -----------------------------------------------------*/

void LCD1602_Init();   //1602初始化

void LCD1602_ReadBusy();

void LCD1602_Clear();

void LCD1602_WriteCmd(uint8_t cmd);

void LCD1602_WriteData(uint8_t dat);

void LCD1602_SetCursor(uint8_t x, uint8_t y);



/* 函数体 -----------------------------------------------------------*/

/*

/*

 * 功能: LCD1602 忙检测函数

 * 参数: None

 * 返回: None

 * 说明: 判断bit7是0,允许执行;1禁止

 */

void LCD1602_ReadBusy()

{

    uint8_t sta;

    LCD1602_DB = 0xff;

    LCD1602_RS = 0;

    LCD1602_RW = 1;

    do

    {

        LCD1602_EN = 1;

        sta = LCD1602_DB;

        LCD1602_EN = 0;         //使能,用完就拉低,释放总线

    }

    while(sta & 0x80);

}

/**

 * @brief: LED1602清屏程序

 * @param: None

 * @return: None

 * @note: None

 */

void LCD1602_Clear()

{

    LCD1602_WriteCmd(0x01);

}

/*

 * 功能: LCD1602 写命令函数

 * 参数: None

 * 返回: None

 * 说明: None

 */

/*void LCD1602_WriteCmd(uint8_t cmd)

{

    LCD1602_ReadBusy();

    LCD1602_RS = 0;

    LCD1602_RW = 0;

    LCD1602_DB = cmd;

    LCD1602_EN = 1;

    LCD1602_EN = 0;

} */

void LCD1602_WriteCmd(uint8_t cmd)

{

    LCD1602_ReadBusy();

    LCD1602_RS = 0;

    LCD1602_RW = 0;

    LCD1602_DB = cmd;

    Delay_ms(2);

    LCD1602_EN = 1;

    Delay_ms(2);

    LCD1602_EN = 0;

}

/*

 * 功能: LCD1602 写数据函数

 * 参数: None

 * 返回: None

 * 说明: None

 */

void LCD1602_WriteData(uint8_t dat)

{

    LCD1602_ReadBusy();

    LCD1602_RS = 1;

    LCD1602_RW = 0;

    LCD1602_EN = 1;

    Delay_ms(2);

    LCD1602_DB = dat;

    Delay_ms(2);

    LCD1602_EN = 0;

}

/**

 * @brief: LCD1602滚动显示函数

 * @param: flag

 * @return: None

 * @note: 输入0不滚动屏幕,输入1左移,输入2右移

 */

void LCD_run(uint8 flag)

{

    switch (flag)

    {

    case 0:

        LCD1602_WriteCmd(0x06);

        break;

    case 1:

        LCD1602_WriteCmd(0x18);

        break;

    case 2:

        LCD1602_WriteCmd(0x1C);

        break;

    default:

        break;

    }

}

/*

 * 功能: LCD1602 坐标显示函数

 * 参数: None

 * 返回: None

 * 说明: None

 */

void LCD1602_SetCursor(uint8_t x, uint8_t y)

{

    uint8_t addr;

    if(y == 0)

        addr = 0x00 + x;

    else

        addr = 0x40 + x;



    LCD1602_WriteCmd(addr | 0x80);

}



/*

 * 功能: LCD1602 按指定位置显示一个字符函数

 * 参数: None

 * 返回: None

 * 说明: None

 */

void LCD1602_DisplayChar(uint8_t x, uint8_t y, uint8_t dat)

{

    y &= 0x1;

    x &= 0xF;                        //限制x不能大于15,y不能大于1

    if (y) x |= 0x40;                //当要显示第二行时地址码+0x40;

    x |= 0x80;                       //算出指令码

    LCD1602_WriteCmd(x);             //发命令字

    LCD1602_WriteData(dat);          //发数据

}

/*

 * 功能: LCD1602 显示字符串函数

 * 参数: None

 * 返回: None

 * 说明: None

 */

void LCD1602_ShowString(uint8_t x, uint8_t y, uint8_t *str)

{

    LCD1602_SetCursor(x, y);            //当前字符的坐标

    while(*str != '\0')

    {

        LCD1602_WriteData(*str++);

    }

}

/*

 * 功能: LCD1602 初始化函数

 * 参数: None

 * 返回: None

 * 说明: None

 */

void LCD1602_Init()

{

    Delay_ms(15);

    LCD1602_WriteCmd(0x38);

    Delay_ms(5);

    LCD1602_WriteCmd(0x38);

    Delay_ms(5);

    LCD1602_WriteCmd(0x38); // 设置显示模式

    LCD1602_WriteCmd(0x0C); // 开显示,显示光标,光标不闪烁

    LCD1602_WriteCmd(0x06); // 光标右移,屏幕不移动

    LCD1602_Clear();        // 清屏

}

/**

/*

 * 功能: 返回值=X的Y次方

 * 参数: None

 * 返回: None

 * 说明: None

 */

int LCD_Pow(int X,int Y)

{

    unsigned char i;

    int Result=1;

    for(i=0;i<Y;i++)

    {

        Result*=X;

    }

    return Result;

}

/*

 * 功能: LCD1602 显示数字

 * 参数: None

 * 返回: None

 * 说明: None

 */

void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)

{

    unsigned char i;

    LCD1602_SetCursor(Line,Column);

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

    {

        LCD1602_WriteData(Number/LCD_Pow(10,i-1)%10+'0');

    }

}

/*>>>>>>>>>> (C) COPYRIGHT NBUFE <<<<<< >>>>>> END OF FILE <<<<<<<<<<*/

3.4 按键服务模块的设计与实现

3.4.1包含头文件及其他参数

包含头文件 "keyScan.h"。

声明外部变量 KeySec、sum 和 k。`KeySec`表示被触发的按键编号。

定义全局变量 a 和 l,用于存储临时数据。

定义了一些自定义字符的字模数据,存储在 Data_0、Data_1、Data_2 和 xiao 数组中。

3.4.2 独立按键函数体流程

实现函数 `key_service()`,用于处理按键服务。在函数中使用 `switch` 语句根据 `KeySec` 的值进行不同的操作:

当 `KeySec` 为 1 时,表示1号键双击触发,LED1602显示右移,然后将 `KeySec` 清零,发出蜂鸣声,延时500毫秒。

当 `KeySec` 为 2 时,表示2号键短按触发,增加变量 k 的值。如果 k 的值大于等于8,将 k 的值重置为0。根据 k 的值,左移P0口的数据。在LCD1602上显示变量 k 的数值。然后将 `KeySec` 清零,发出蜂鸣声,延时500毫秒。

当 `KeySec` 为 22 时,表示2号键长按触发,如果 k 的值小于等于0,将 k 的值设置为7。否则减小变量 k 的值。根据 k 的值,左移P0口的数据。在LCD1602上显示变量 k 的数值。将 KeySec 的值清零,发出蜂鸣声,延时500毫秒。

当 `KeySec` 为 3 时,表示3号键短按触发,LED1602显示左移,然后将 `KeySec` 清零,发出蜂鸣声,延时500毫秒。

当 `KeySec` 为 33 时,表示3号键长按连续步进触发,与3号键短按操作类似。

当 `KeySec` 为 4 时,表示4号键短按触发,初始化LED1602。写入自定义字符字模数据。在LED1602上显示特定的字符。然后将 `KeySec` 清零,发出蜂鸣声,延时500毫秒。

当 `KeySec` 为 44 时,表示4号键长按触发,初始化LED1602。写入自定义字符字模数据。在LED1602上显示特定的字符。然后将 `KeySec` 清零,发出蜂鸣声,延时500毫秒。

这段代码的主要思路是通过检测按键的触发,根据不同的按键编号执行相应的操作。并在LED1602上显示相关信息和控制蜂鸣器的状态。在每次处理完按键操作后,通过蜂鸣器发出短暂的声音来提供音频反馈。

 4  总结与展望     

                                                   

4.1 总结

本报告详细介绍了基于STC8A8K64D4微控制器的炫彩灯光系统的设计与实现。首先,对国内外研究现状进行了综述,概述了炫彩灯光系统的应用背景和相关技术。然后,对系统的总体设计进行了阐述,包括系统功能、硬件环境搭建、硬件描述以及LED1602显示模块的详细介绍。接着,详细介绍了系统环境的搭建过程,包括软件环境和开发工具的选择与配置。随后,对硬件环境进行了扩写,详细描述了各个硬件模块的功能和连接方式。

4.2 展望

基于STC8A8K64D4的炫彩灯光系统为灯光表演提供了一种简单而有效的解决方案。然而,作为一个基础的炫彩灯光系统,还有许多方面可以进一步扩展和改进:

增加灯光模式:在当前的基础上,继续扩展灯光模式,例如音乐律动、跳动效果、跑马灯等,增加更多的灯光变化和动态效果。

外部控制接口:添加外部控制接口,如UART、SPI或I2C等,以便通过外部设备或主控制器控制炫彩灯光系统,实现更高级的功能和集成。

引入音频响应:通过麦克风或音频输入接口,使灯光系统能够根据音频信号的频率、强度和节奏做出灯光的变化和反应,增加音乐表演效果。

优化灯光控制算法:通过优化灯光控制算法和使用更高级的调光技术,提高灯光变化的流畅性和精确性,提供更加出色的灯光效果。

设计用户友好的控制界面:开发配套的手机应用或PC软件,提供直观和友好的用户界面,方便用户控制和定制灯光效果。

综上所述,基于STC8A8K64D4的炫彩灯光系统设计与实现在灯光显示方面提供了一个可靠的解决方案,并具有进一步拓展和改进的潜力。随着技术的不断发展,炫彩灯光系统将在更广泛的领域中发挥重要作用。

4.3 心得体会

通过对基于STC8A8K64D4的炫彩灯光系统的设计与实现的研究和探索,我深刻体会到了硬件与软件的结合在物联网应用中的重要性。在这个项目中,我不仅学习到了硬件环境搭建的方法和步骤,还深入了解了STC8A8K64D4微控制器的特性和使用方法。同时,我也加深了对麦克风音量传感器、AD转换器和液晶显示模块等硬件设备的理解。

在软件方面,我学习了如何编写与STC8A8K64D4微控制器兼容的代码,以实现数据的获取、处理和显示。我熟悉了嵌入式系统的开发流程和技巧,学会了使用相应的开发工具和调试方法。通过编程,我能够实现与硬件设备的交互,将抽象的声音数据转化为可视化的结果,提高了系统的可用性和用户体验。

此外,通过这个项目,我也更加了解了炫彩灯光系统在现实生活中的广泛应用。

在整个项目的过程中,我也遇到了一些挑战和困难。例如,对硬件的理解和接线的准确性需要认真学习和仔细操作,否则可能会导致系统不稳定或功能失效。此外,编写嵌入式软件需要具备一定的编程基础和逻辑思维能力,对编程语言和开发工具的熟练度也有一定要求。因此,在项目中需要持续学习和探索,解决问题和优化系统的能力也是必不可少的。

总的来说,基于STC8A8K64D4的炫彩灯光系统的设计与实现是一项具有挑战性和实用性的项目。通过这个项目,我不仅掌握了嵌入式系统的开发方法和技巧,还深入了解了AD测量和显示的原理和应用。这对我的专业知识和技能提升有着积极的影响,并且培养了我解决问题和创新思维的能力。我相信在将来的学习和工作中,这些经验和知识都会发挥重要的作用,并为我进一步深入研究和应用物联网领域打下坚实的基础。

视频:

基于STC8A8K64D4的炫彩灯光的设计与实现

PWM (Pulse Width Modulation) 模块在基于 STC8A8K64D4 单片机的RGB呼吸灯设计中,主要用于控制灯光的颜色和亮度变化。首先,你需要了解以下几个关键步骤: 1. **硬件准备**:连接RGB LED到单片机的 PWM 输出端口,通常每个颜色(红、绿、蓝)占用一个独立的 PWM 引脚。 2. **软件配置**: - 安装必要的库或头文件,以便利用单片机的 PWM 功能。 - 初始化 PWM 控制器,设置周期(占空比的最大值)和初始 duty cycle(占空比的比例)为0。 3. **定时器管理**:启用定时器,通过改变 PWM 的 duty cycle 来模拟灯光的明暗变化。例如,渐增或渐减 duty cycle 可以创建呼吸效果。 4. **颜色处理**: - 将 RGB 颜色转换为 PWM 信号的三个分量,比如红色对应高电平时间,绿色和蓝色也分别有对应的 PWM 时间比例。 - 更新每个颜色通道的 PWM duty cycle,并同步更新整个RGB灯的亮度。 5. **循环更新**:在主循环中不断调整 PWM duty cycle,创建呼吸频率和色彩变化的效果。 下面是一个简化的伪代码示例: ```c #include <stm8s.h> void setup_PWM(void) { TIMx->CCR1 = 0; // 初始化 PWM 通道1为低电平 TIMx->CCR2 = 0; TIMx->CCR3 = 0; TIMx->CR1 |= (TIM_CR1_CEN | TIM_CR1_PSC_DIV8); // 启动定时器并设置预分频 } void update_RGB_PWM(uint8_t r, uint8_t g, uint8_t b) { TIMx->CCR1 = r * PULSE_WIDTH_R / 255; TIMx->CCR2 = g * PULSE_WIDTH_G / 255; TIMx->CCR3 = b * PULSE_WIDTH_B / 255; } void main(void) { setup_PWM(); while(1) { // 更新RGB值并触发颜色变化 r++; g++; b++; if (r > 255 || g > 255 || b > 255) { r = 0; g = 0; b = 0; } update_RGB_PWM(r, g, b); TIMx->ICR = TIMx->ARR; // 计数溢出后自动重置计数器 } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我也想知道why

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值