学习笔记|回顾(1-12节课)|应用模块化的编程|添加函数头|静态变量static|STC32G单片机视频开发教程(冲哥)|阶段小结:应用模块化的编程(上)

文章目录

  • 1.回顾(1-12节课)
  • 2.应用模块化的编程(.c + .h)
    • Tips:添加函数头
    • 创建程序文件三步
    • 引脚定义都在.h文件
    • 函数定义三步
    • bdata位寻址变量的使用
  • 3.工程文件编写
    • 静态变量static的使用
    • 完整程序为:
      • demo.c:
      • seg_led.c:
      • seg_led.h:

1.回顾(1-12节课)

一、认识单片机
二、了解单片机硬件(介绍开发板)
三、开发环境搭建和下载,新工程建立资料下载
四、点亮点一个LED(CDC和HID下载)		--GPIO
五、C语言运算符和进制数入门
六、LED闪烁和花式点灯       			--GPIO
七、按键点亮灯					--GPIO
八、蜂鸣器					--GPIO
九、数码管的静态使用				--GPIO
十、数码管动态点亮 				--GPIO
十一、定时器					--TIM
十二、计数器的使用				--TIM

重点理清程序的逻辑思路。重点理清程序的逻辑思路。重点理清程序的逻辑思路。什么时候打开LED?LED打开多久?什么时候切换数码管显示?什么时候按键按下触发什么功能?
之前的课主要是带大家熟悉写程序的方法,分析逻辑,实现我们要的功能。
那么这一节课开始,我们要规范程序,符合我们工程师级别的代码规范。

2.应用模块化的编程(.c + .h)

一、LED & 数码管 --led_seg.c, led_seg.h
二、按键 --key.c, key.h
三、蜂鸣器 --beep.c, beep.h
四、定时器 --tim.c, tim.h
一个功能对应一个.c和.h

Tips:添加函数头

//========================================================================
// 函数名称:
// 函数功能:
// 入口参数: @
// 函数返回:
// 当前版本: VER1.0
// 修改日期: 2023
// 当前作者:
// 其他备注:
//========================================================================
在keil中设置:
学习笔记|回顾(1-12节课)|应用模块化的编程|添加函数头|静态变量static|STC32G单片机视频开发教程(冲哥)|阶段小结:应用模块化的编程(上)_第1张图片

学习笔记|回顾(1-12节课)|应用模块化的编程|添加函数头|静态变量static|STC32G单片机视频开发教程(冲哥)|阶段小结:应用模块化的编程(上)_第2张图片
添加后,重启软件就可以使用了。

创建程序文件三步

新建文件并保存
添加到工程
添加引用路径

引脚定义都在.h文件

sbit 名称 = P10;
#define 名称 P10

函数定义三步

定义
声明
调用

修饰符extern用在变量或者函数的声明前,用来说明“此变量/函数是在别处定义的,要在此处引用”。
举例1:如果文件a.c需要引用b.c中变量int v,就可以在a.c中声明extern int v,然后就可以引用变量v。
举例2:如果文件a.c需要引用b.c中变量int v,就可以在b.h中声明extern int v,然后a.c调用b.h就可以引用变量v。
注意extern修饰的变量不能赋初值。
详细介绍可参考:extern关键字,C语言extern关键字用法详解。

bdata位寻址变量的使用

a.c a.h
u8 bdata LED = 0x00; extern u8 bdata LED;
sbit LED0 = LED^0; extern bit LED0;
sbit LED1 = LED^1; extern bit LED1;

3.工程文件编写

学习笔记|回顾(1-12节课)|应用模块化的编程|添加函数头|静态变量static|STC32G单片机视频开发教程(冲哥)|阶段小结:应用模块化的编程(上)_第3张图片
学习笔记|回顾(1-12节课)|应用模块化的编程|添加函数头|静态变量static|STC32G单片机视频开发教程(冲哥)|阶段小结:应用模块化的编程(上)_第4张图片

学习笔记|回顾(1-12节课)|应用模块化的编程|添加函数头|静态变量static|STC32G单片机视频开发教程(冲哥)|阶段小结:应用模块化的编程(上)_第5张图片
因为他们公用P6端口,所以给他们放在了一个文件。

之前的程序是在定时器中通过一个函数刷新数码管,现在就要给他增加刷新LED的功能。这里刷新显示,在别的地方赋值。
利用上节的文件,复制成工程9.TIM多任务,进入,新建目录(路径)HARDWARE,所有子程序都放入,本次要写的4个功能分别建立4个文件夹,留着备用:
学习笔记|回顾(1-12节课)|应用模块化的编程|添加函数头|静态变量static|STC32G单片机视频开发教程(冲哥)|阶段小结:应用模块化的编程(上)_第6张图片
打开project,选择Add New ltem to Group ‘source Group 1’…
学习笔记|回顾(1-12节课)|应用模块化的编程|添加函数头|静态变量static|STC32G单片机视频开发教程(冲哥)|阶段小结:应用模块化的编程(上)_第7张图片

就可以在LED目录中新建seg_led.c和seg_led.h:
学习笔记|回顾(1-12节课)|应用模块化的编程|添加函数头|静态变量static|STC32G单片机视频开发教程(冲哥)|阶段小结:应用模块化的编程(上)_第8张图片

添加引用路径:
学习笔记|回顾(1-12节课)|应用模块化的编程|添加函数头|静态变量static|STC32G单片机视频开发教程(冲哥)|阶段小结:应用模块化的编程(上)_第9张图片

至此,工程文件模板就建立了。
seg_led.h修改,添加infdef预定义:

#ifndef __SEG_LED_H
#define __SEG_LED_H

#include "COMM/stc.h"		//调用头文件
#include "COMM/usb.h"

#endif

可以将此预定义存为template,方便使用。
在seg_led.c和demo.c中都增加对seg_led.h的调用。
将demo.c中数码管的功能移植至seg_led.c中:

u8 SEG_Tab[21] = { 0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90, 0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10,0xff};	//共21个字节:0-9段码共10个,0-9带小数点共10个,全部不显示共1个,
u8 COM_Tab[8] = { 0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe };																	//0-7的位码数组
u8 Show_Tab[8] = {20,20,20,20,20,20,20,20};

静态变量static的使用

如果要在其他文件中控制变量Show_Tab用于显示,则需要将其放在.h文件中作为外部变量:extern u8 Show_Tab[8];,之后就可以在主函数里调用。
移植void SEG_Fre(void)函数至seg_led.c,并在函数体中增加static 变量,静态变量,只有第一次执行的时候再赋初始值,定义:static int num = 0;,后面不再赋值。
如果不加static,每次进入函数后都会重新赋为0 ,不会刷新第2位以后的值,故需要使用静态变量,只赋值一次。
需要在seg_led.h中声明一下:void SEG_Fre(void);
删除或注释掉demo.c中原程序代码的计数器初始化部分:

//	TMOD = 0x50;			//设置计数器模式   
//	TL1 = 0x00;				//设置计数初始值
//	TH1 = 0x00;				//设置计数初始值
//	TF1 = 0;				//清除TF1标志
//	TR1 = 1;				//定时器1开始计时
//	ET1 = 1;				//使能定时器1中断
//	    
//	P3PU = 0x20; 			//打开内部上拉4.1K

删除主函数中冗余代码,留定时器0初始化。
在主程序demo.c文件中加入数码管赋初值。

	//数码管初始化,显示0-7:
	Show_Tab[0] = 0;
	Show_Tab[1] = 1;
	Show_Tab[2] = 2;
	Show_Tab[3] = 3;
	Show_Tab[4] = 4;
	Show_Tab[5] = 5;
	Show_Tab[6] = 6;
	Show_Tab[7] = 7;

在.h文件中增加引脚定义:

//------------------------引脚定义------------------------//
#define SEG_SEG P6
#define SEG_COM P7
#define LED_POW P40 	//P40是led的电源开关

编译,选目标文件,下载完成,数码管显示0-7,但led还是不亮,需要加入相应点亮刷新代码。
seg_led.h中定义LED的显示变量和电源开关:

extern u8 LED_DATA;		//LED的显示变量

#define LED_POW P40 	//P40是led的电源开关

增加引脚定义:
seg_led.c中更新刷新函数SEG_Fre:

void SEG_Fre( void )
{
	static int num = 0;

	if(num <=7 )						//num==0-7的执行
	{
		LED_POW = 0;					//关闭LED电源
		SEG_COM = COM_Tab[num];			//相应数码管位码的选择
		SEG_SEG = SEG_Tab[Show_Tab[num]];//需要显示的数字的内码
	}

	else if ( num <= 8 )				//num==8的执行
	{
		LED_POW = 0;					//LED刷新,打开电源
		SEG_COM = 0xff;					//关闭数码管
		SEG_SEG = LED_DATA;				//输出LED状态
	}
	else								//num==9的执行
	{
		LED_POW = 1;					//LED关闭电源
		SEG_COM = 0xff;					//关闭数码管
		SEG_SEG = 0xff;					//关闭所有段码信号
	}

	num++;
	if( num >=10 )
		num = 0;						//num清零
}

demo.c中对LED赋初值:

LED_DATA = 0x0f;	//赋初值,亮一半灭一半

完整程序为:

demo.c:

#include "COMM/stc.h"		//调用头文件
#include "COMM/usb.h"
#include "seg_led.h"

#define KEY1 P32		//定义一个按键 引脚选择P32
#define KEY2 P33		//定义一个按键 引脚选择P33

#define BEEP P54		//定义一个按键 引脚选择P54

#define SEG_Delay  1	//延时多少ms

#define MAIN_Fosc 24000000UL	//定义主时钟

char *USER_DEVICEDESC = NULL;
char *USER_PRODUCTDESC = NULL;
char *USER_STCISPCMD = "@STCISP#";


u32 TimCount = 0;		//计数单位1ms
bit RUN_State = 0;		//开始运行/结束运行
u8 num = 0;
u16 Count_T1 = 0;

void sys_init();	//函数声明
//void delay_ms(u16 ms);	//unsigned int
//void INT1_Isr(void);
void Timer0_Isr(void);




void main()					//程序开始运行的入口
{

	sys_init();				//USB功能+IO口初始化
	usb_init();				//usb库初始化

	EA = 1;					//CPU开放中断,打开总中断。

	//数码管初始化,显示0-7:
	Show_Tab[0] = 0;
	Show_Tab[1] = 1;
	Show_Tab[2] = 2;
	Show_Tab[3] = 3;
	Show_Tab[4] = 4;
	Show_Tab[5] = 5;
	Show_Tab[6] = 6;
	Show_Tab[0] = 7;

	LED_DATA = 0x0f;	//赋初值,亮一半灭一半

	while(1)		//死循环
	{
		if( DeviceState != DEVSTATE_CONFIGURED ) 	//
			continue;
		if( bUsbOutReady )
		{
			usb_OUT_done();

		}

	}
}

void sys_init()		//函数定义
{
    WTST = 0;  //设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
    EAXFR = 1; //扩展寄存器(XFR)访问使能
    CKCON = 0; //提高访问XRAM速度

	P0M1 = 0x00;   P0M0 = 0x00;   //设置为准双向口
    P1M1 = 0x00;   P1M0 = 0x00;   //设置为准双向口
    P2M1 = 0x00;   P2M0 = 0x00;   //设置为准双向口
    P3M1 = 0x00;   P3M0 = 0x00;   //设置为准双向口
    P4M1 = 0x00;   P4M0 = 0x00;   //设置为准双向口
    P5M1 = 0x00;   P5M0 = 0x00;   //设置为准双向口
    P6M1 = 0x00;   P6M0 = 0x00;   //设置为准双向口
    P7M1 = 0x00;   P7M0 = 0x00;   //设置为准双向口

    P3M0 = 0x00;
    P3M1 = 0x00;

    P3M0 &= ~0x03;
    P3M1 |= 0x03;

    //设置USB使用的时钟源
    IRC48MCR = 0x80;    //使能内部48M高速IRC
    while (!(IRC48MCR & 0x01));  //等待时钟稳定

    USBCLK = 0x00;	//使用CDC功能需要使用这两行,HID功能禁用这两行。
    USBCON = 0x90;
}


//void delay_ms(u16 ms)	//unsigned int
//{
//	u16 i;
//	do
//	{
//		i = MAIN_Fosc/6000;
//		while(--i);
//	}while(--ms);
//}

void Timer0_Isr(void) interrupt 1 //1ms进来执行一次,无需其他延时,重复赋值
{
	SEG_Fre();		//数码管刷新1ms执行一次

}

//void INT1_Isr(void) interrupt 3 //计时器中断
//{
//	//P60 = !P60; //led取反
//}

seg_led.c:

#include "seg_led.h"

u8 SEG_Tab[21] = { 0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90, 0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10,0xff};	//共21个字节:0-9段码共10个,0-9带小数点共10个,全部不显示共1个,
u8 COM_Tab[8]  = { 0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe };																	//0-7的位码数组
u8 Show_Tab[8] = {20,20,20,20,20,20,20,20}; 																					//数码管显示数组,上电后,全部关闭显示
//u8 LED_DATA  =  0xff;																											//LED初始全部熄灭

void SEG_Fre( void )
{
	static int num = 0;

	if(num <=7 )						//num==0-7的执行
	{
		LED_POW = 0;					//关闭LED电源
		SEG_COM = COM_Tab[num];			//相应数码管位码的选择
		SEG_SEG = SEG_Tab[Show_Tab[num]];//需要显示的数字的内码
	}

	else if ( num <= 8 )				//num==8的执行
	{
		LED_POW = 0;					//LED刷新,打开电源
		SEG_COM = 0xff;					//关闭数码管
		SEG_SEG = LED_DATA;				//输出LED状态
	}
	else								//num==9的执行
	{
		LED_POW = 1;					//LED关闭电源
		SEG_COM = 0xff;					//关闭数码管
		SEG_SEG = 0xff;					//关闭所有段码信号
	}

	num++;
	if( num >=10 )
		num = 0;						//num清零
}

seg_led.h:

#ifndef __SEG_LED_H
#define __SEG_LED_H

#include "COMM/stc.h"		//调用头文件
#include "COMM/usb.h"

extern u8 Show_Tab[8];		//数码管的内码显示变量
extern u8 LED_DATA;		//LED的显示变量


//------------------------引脚定义------------------------//
#define SEG_SEG P6
#define SEG_COM P7
#define LED_POW P40 	//P40是led的电源开关

void SEG_Fre(void);  		//仅声明

#endif

你可能感兴趣的:(STC32,学习,笔记,单片机)