sdwflzg
发表于 2023-6-15 15:40:10
第六集(上)
注意事项
STC-ISP需要保持最新版
一、LED闪烁
#include "com/stc.h"
#defineMAIN_Fosc 24000000UL //定义一个IRC系统时钟
void delay_ms(u16 ms)//u16 在stc.h中进行了定义
{
u16 i;
do
{
i=MAIN_Fosc/6000; //计算出1ms需要循环段次数
while(--i);
}while(--ms);
}
循环语句的使用
while()
do {
...
} while()
变量自减
a-- //先输出再自检
a=10;
b=a--; // b=10 ,a=9
--a //先自减再输出
a=10;
b=--a; // b=9 ,a=9
第六集(下)
二、函数的使用
在模块化编程里,函数使用分为如下三步:
1:函数定义
返回值 函数名称(入口参数)
{
函数要执行的功能;
return 返回值;(无返回值可不写)
}
@返回值:没有返回值就是 void
@函数名称:避开关键词,不重复,非特殊字符随便取
@入口参数:类型 + 名称,多个参数“,“分开,空就写 void
2.函数声明
返回值函数名称(入口参数);
3.函数调用
函数名称(入口参数):
三、新建文件,使用模块化编程
新建 xxx.c 和 xxx.h 文件,代表一个功能块。
xxx.h 格式:
#ifndef __XXX_H
#define __XXX_H
调用头文件
函数声明...
#endif
xxx.c 格式
#include"xxx.h"
函数定义
添加文件定定要记得引用路径和添加到工程里。
sdwflzg
发表于 2023-6-19 11:03:07
本帖最后由 sdwflzg 于 2023-6-19 11:05 编辑
第七集
按键点灯
提示:
选中一列代码:Alt+Shift+按下鼠标左键移动选择要复制的列。
一定要记住整个程序是在一个大循环中进行
左移(<<)最低位补1的方法: x=(x<<1)+1;
1、按键的代码实现过程
按下按键就执行
if(KEY == 0)
{
Delay_ms(10);
if(KEY ==0)
{
执行功能
}
}
按键松手后再执行
if(KEY == 0)
{
Delay_ms(10);
if(KEY ==0)
{
while(KEY==0); //松手检测
执行功能
}
}
按键编程消抖是关键,一种方法是用延时软件达到消抖。
2、数组的使用
数组使用分为如下两步:
1.定义
类型名称[长度]={数值};
例如:
usigned char x={23,43,41};
2.使用
赋值:名称[索引]= 数值
调用:名称[索引]
索引从0开始
sdwflzg
发表于 2023-6-19 15:38:03
第八集
提示:
! 是逻辑运算符(非零即一、非真即假)
~ 位运算符(按位取反)
蜂鸣器
蜂鸣器分为有源蜂鸣器、无源蜂鸣器。
有源蜂鸣器控制原理
本集是对键盘、LED、蜂鸣器的综合应用,并阐述了怎样根据需求进行编程设计-先理清思路,再回过头来写代码。独立完整的完成本集示例是对前面几集知识很好的巩固。
sdwflzg
发表于 2023-6-20 14:40:43
第九集
提示
1、电子表格常用不同进制间转换函数
16进制转10进制:HEX2DEC
16进制转2进制:HEX2BIN
10进制转16进制:DEC2HEX
10进制转2进制:DEC2BIN
2进制转16进制:BIN2HEX
2进制转10进制:BIN2DEC
2、文件名用中文名有时编译会出错。
数码管的静态使用
数码管分为共阴极和共阳极,型号尾缀A表示共阳极,K表示共阴极。
1、 共阳极数码管显示数字对应的段码
10进制段码数组 {192,249,164,176,153,146,130,248,128,144}
16进制段码数组 {0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90}
2、共阴极数码管显示数字对应的段码
10进制段码数组 {63,6,91,79,102,109,125,7,127,111}
16进制段码数组 {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F}
共阳和共阴数码管断码是相互按位取反的关系
3、点亮一个数码管,单片机需要输出位选和段码数据。
sdwflzg
发表于 2023-6-21 15:01:06
第十集
数码管动态刷新的原理
需要注意每个延时不能太短,我们这边程序就以 1ms 为准,且需要保证总共一个循环结束的时间不能大于 20ms,因为人眼的视觉不容易分辨出50HZ 以上的动态刷新。
需要一个位码数组(或使用_crol_()函数)
十进制位码数组 {127,191,223,239,247,251,253,254}
二进制位码数组 {0x7F,0xBF,0xDF,0xEF,0xF7,0xFB,0xFD,0xFE}
包含小数点的16进制段码数组 {0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10}
例如:如果取3的断码数组下标为3,如果取3加小数点的断码下标13。
再建一个显示每位显示内容的数组。
重复的代码段我们可以将其定义为一个函数。
sdwflzg
发表于 2023-6-27 15:00:39
第十一集
定时器/计数器(用T0实现每1ms产生1次中断)
1、软件定时的缺点:占用CPU时间,影响CPU的运行效率和处理速断,有时会造成很大的定时误差。
2、中断的概念:中断请求、中断响应(中断处理程序)、中断返回,本节主要是讲定时器中断。
3、定时器的使用(以T0为例)
1)设置为定时器/计数器
寄存器TMOD的T0_CT位:0为定时模式,1为计数模式
2)设置不分频或12分频
通过设置辅助寄存器AUXR的T0x12:0为12分频(默认为0),1为不分频。
3)定时器工作模式T0_M1/T0_M0
16位自动重载模式比较常用。
4)定时器设置 (定时器 0/1 控制寄存器TCON)
TF0:T0 溢出中断标志。该位软件清0,也可以不清0。
TR0:定时器 T0 的运行控制位。该位软件置1,开启定时器。
5)中断
IE:中断使能寄存器,EA:总中断允许控制位。EA=1允许中断。
ET0:定时 / 计数器 T0 的溢出中断允许位。ET0=1允许定时器中断。
4、实现T0定时器中断的主要程序
T0初始化程序
TMOD =0x00; // 设置定时器 0 位 16 位自动重载模式
TL0=0x30; // 计算出的 24M 时钟下的 1ms 的定时时间初始值
TH0=0xF8:
TR0=1; //启动定时器
ET0 =1; // 使能定时器中断
EA = 1; //CPU 开放中断,打开总中
T0中断响应程序
void Tim0_Isr() interrupt 1 //1-定时器0中断号
{
}
利用STC-ISP的“定时器计算器”自动生成定时器初始化程序
5、建议
中断发生的频率越低越好。
中断程序执行的代码越少越好。
sdwflzg
发表于 2023-6-28 17:05:59
本帖最后由 sdwflzg 于 2023-6-28 17:07 编辑
第十二集
计数器的使用(以定时器1为例)
1、计数器的用途
只要输出信号带高低电平变化,想要计算个数的就可以用计数器的功能。
2、计数器的配置
T1_C/T:控制定时器1用作定时器或计数器。T1_C/T=1为计数器
T1_GATE:控制定时器 1,置 1 时只有在 INT1 脚为高及 TR1 控制位置 1 时才可打开定时器 / 计数器 1。此例将T1_GATE清零。
3、计数器的使用
STC-ISP I/O配置工具
文件名和路径名中不能使用GB 2312 中,包含 Oxfd 编码的汉字如下:
褒饼昌除待谍洱俘庚过糊积箭烬君魁例笼慢谬凝琵讫驱三升数她听妄锡淆旋妖引育札正铸佚冽邶埤荦蔟摭啐帻猃恺泯潺妪纨琮椠挲臊忑睚铨稞瘕颀螨簖酏觚鳊鼾
定时器1计数器初始化代码:
TMOD=0x40; // 设置计数器模式
TL1=0xFF; // 设置计数初始值
TH1=0xFF; // 设置计数初始值
TF1=0; // 清除 TF1 标志
TR1=1; // 定时器 1 开始计时
ET1=1; // 使能定时器 1 中断
P3PU=0x20; //打开内部4.1k上拉电阻
定时器1中断响应函数
void Tim1_Isr() interrupt 3 //3-定时器1中断号
{
}
4、计数器应用实例
关键代码
数码管不显示的段码:0xFF
void Timer0_Isr(void) interrupt 1
{
TinCount++; // 每隔 1ms+1,计数到 2000=2s
if(TimCount>=2000) //2 秒定时时间到了
{
TinCount = 0;
Count_T1=(TH1 *256)+ TL1; //读取计数器的值,
TH1=0;
TL1=0;
Show_Tab= Count T1/1000%10;
Show_Tab=Count_T1/100%10;
Show_Tab=Count_T1/10%10;
Show_Tab=Count_T1/1%10:// 取 10 位
SEG_Fre(); // 数码管刷新的
}
}
sdwflzg
发表于 2023-7-4 16:44:41
第十三集
理清思路
模块化编程
编写程序规范化
这一集信息量较大,学起来有点困难,正在努力。{:4_246:}
sdwflzg
发表于 2023-7-19 10:19:40
本帖最后由 sdwflzg 于 2023-7-19 10:21 编辑
第十三集确实不好啃,视频至少看3次了!
sdwflzg
发表于 2023-7-19 11:08:19
第十三集
首先冲哥老师现场编程的教学方法非常值得称赞!
十三集终于啃完了,祝贺一下!
简易多任务
理清思路
模块化编程
编写程序规范化
函数需要加注释,以便后期维护和其他开发者使用
注释一般包含:
//========================================
// 函数名称:
// 函数功能:
// 入口参数:@
// 函数返回:
// 当前版本:VER 1.0
// 修改日期:2023
// 当前作者:
// 其他备注:
//=========================================
规范编程中关键语句的注释非常必要
Keil中模板的使用
创建程序文件三步
新建文件并保存
添加到工程 (添加.c文件)
添加引用路径
引脚定义都在.h 文件
sbit 名称 = P10;
#define 名称 P10
函数定义三步
定义
声明
调用
修饰符 extern 的使用
修饰符 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 修饰的变量不能赋初值。
bdata 位寻址变量的使用
a.c
u8 bdata LED = 0x00;
sbit LED0 = LED^0;
sbit LED1 = LED^1;
a.h
extern u8 bdata LED;
extern bit LED0;
extern bit LED1;
(在a.h中定义后,可在任何一个.c中调用这些变量)
注意定义时用sbit,在extern声明时用bit
模块化程序的编写
一个模块需要.c和.h两个文件,以seg_led为例:
seg_led.c
#include "seg_led.h"
seg_led.h
#ifndef __SEG_LED_H
#define__SEG_LED_H
//------------------调用头文件------------------
//------------------引脚定义---------------------
//------------------变量声明---------------------
//------------------函数声明---------------------
#endif
同时在要调用的程序(主程程序)中加入
#include "seg_led.h"
static 变量类型 变量名=初值;
静态变量,只在第一次执行时赋初值。
按键
LastState |= (1<<i); //“与等于”相应的标志位置位
LastState &= (1<<i); //“或等于”相应的标志位清零
按键函数听上去有点懵!
定时器函数
中断函数写在主程序中
学习总结
这一集的内容非常关键,几个常用函数用途非常广泛,掌握这个编程思路,在今后实际工程开发中会起到重要作用。
模块化编程,随着开发的进程,模块越来越多,编程会越来越方便。更换不同的板子会变得很方便。