Rain_Personal
发表于 2024-4-26 20:28:13
本帖最后由 Rain_Personal 于 2024-4-26 20:37 编辑
第九课 数码管的静态使用
1. 什么时数码管
数码管就是LED灯,根据发光二极管的正负极可以分为共阳和共阴数码管,LED灯负极接在一起的就是共阴,LED数码管正极接在一起的就是共阳
每个灯表示一个段,每8个灯表示一个位,根据课后作业推算出来的各个字母的描述其中N的描述应该时11.。没有想到其他方法,只能用dp区分了。
根据每个灯的控制逻辑可以将每个数字所需要亮的灯用16进制描述。
首先需要控制共阳/阴极开启一位显示,再根据16进制控制这一位的每个灯开关逻辑
P70 = 0; //开启一个数码管
就是开启一个数码管。
关键代码分析
Rain_Personal
发表于 2024-4-26 21:00:30
本帖最后由 Rain_Personal 于 2024-4-27 08:32 编辑
第十课动态显示数码管
1. 显示原理
其中需要注意每个延时不能太短,我们这边程序就以1ms为准,且需要保证总共一个循环结束的时间不能大于20ms,因为人眼的视觉不容易分辨出50HZ以上的动态刷新。
通过延时的长短可以控制每个灯的显示时间,超过人眼闪烁的分辨率就可以看起开像都显示了。
全部显示不同数字时,可以减少延时时间,看起来像是每位都在显示,其实是每位分别显示,只是频率快,人眼分辨不出来。
逻辑上有点绕,感觉比较复杂。
2. 10秒按键挑战代码分析
void SEG_Fre( void ) //应该是属于刷新数码管
{
//位码选择第一位,段码选择0
P7 = COM_Tab; //位码的选择
P6 = SEG_Tab];//需要显示的数字的内码 赋给 P6 NUM =0 -> Show_Tab] = 1 -> p6 = oxF9
delay_ms(SEG_Delay);
num++;
if( num >7 )
num = 0;
}
Show_Tab= 1; //选择 1
Show_Tab= 10; //选择 0.// 为什么从10开始, 带小数点
Show_Tab= 0; //选择 0
Show_Tab= 0; //选择 0
if( RUN_State==1 )
{
TimCount++;
Show_Tab = TimCount/10000%10;//TimCount/10000,表示有多少个10000,计算万位以上数字 %10 对10取余 表示万位上的数字
Show_Tab = TimCount/1000%10+10; // 加10 带小数点
Show_Tab = TimCount/100%10;
Show_Tab = TimCount/10%10; //取10位
}
SEG_Fre();// 刷新数码管
if( KEY1 ==0 )
{
delay_ms(10);
if( KEY1 ==0 )
{
BEEP = 0;
delay_ms(10);
BEEP = 1;
while( KEY1 ==0 )
{
SEG_Fre();
}
if( RUN_State==0 )
TimCount = 0;
RUN_State = !RUN_State;
}
}
这逻辑秒呀!!!
Rain_Personal
发表于 2024-4-26 21:05:15
本帖最后由 Rain_Personal 于 2024-4-27 08:35 编辑
第十一课 定时器的应用
while(Key==0)会不断循环,函数不会向下运行。
1. 定时器作用
定时器主要是可以自动自增,定时时间,达到固定时间就可以执行想要的不在主程序中的程序段
void Timer0_Init(void) //1毫秒@24.000MHz
{
AUXR &= 0x7F; //定时器时钟12T模式 AUXR为寄存器0x8e 那么后面的都是寄存器的描述,直接赋值寄存器,就是初始化
TMOD &= 0xF0; //设置定时器模式
TL0 = 0x30; //设置定时初始值
TH0 = 0xF8; //设置定时初始值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0 = 1; //使能定时器0中断
}
void Timer0_Isr(void) interrupt 1 // interrupt 关键字
{
SEG_Fre(); //数码管刷新的
if( RUN_State==1 ) //如果开始运行
{
TimCount++; //每隔1ms+1
Show_Tab = TimCount/10000%10;
Show_Tab = TimCount/1000%10+10;
Show_Tab = TimCount/100%10;
Show_Tab = TimCount/10%10; //取10位
}
}
可以通过STCAI-ISP下载器中的所带的功能设置定时器
不使能定时器
void Timer0_Init(void) //1毫秒@24.000MHz
{
AUXR &= 0x7F; //定时器时钟12T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0x30; //设置定时初始值
TH0 = 0xF8; //设置定时初始值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
}
使能定时器ET0的寄存器使能定时器
void Timer0_Init(void) //1毫秒@24.000MHz
{
AUXR &= 0x7F; //定时器时钟12T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0x30; //设置定时初始值
TH0 = 0xF8; //设置定时初始值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0 = 1; //使能定时器0中断
}
Rain_Personal
发表于 2024-4-27 08:58:32
第十二课计数器的应用
使用SYSclk时,是计时器,SYSclk为固定频率,所以可以计数,理论仍是计数。
使用T1 Pin为计数器,可以对电机转速什么的进行计数
Rain_Personal
发表于 2024-4-27 10:05:20
本帖最后由 Rain_Personal 于 2024-4-27 11:48 编辑
第十三课简易多任务处理
1. 模块化编程
打开工程后。需要打开一个c文件才可以显示模块化编程中的模块
打开c文件之后
引脚定义可以用
sbit 名称 = P10;
#define 名称 P10
作业:LED0给他200ms取反一次,LED1给他400ms取反一次,LED2给他800ms取反一次
关键代码
P40 = 0;
// 可采用中断控制LED0LED1 LED2
// LED0200ms
不能生成200ms的程序...
Rain_Personal
发表于 2024-4-27 11:56:15
第十四课矩阵键盘
SW33按下为什么是0,而不是P01是5V???
GND遇到5V会把引脚拉低到0V,而不是5V会把GND拉底到5V!
Rain_Personal
发表于 2024-4-27 14:35:31
第十五课 外部中断
1. 中断系统
多个中断源
2. 外部中断
外部引脚可以触发中断,INT标注的引脚为中断引脚
代码描述
需要首先定义中断 以中断0为例
EA = 1; //CPU开放中断,打开总中断。
IT0 = 1; //1:下降沿中断 0:上升下降沿中断
EX0 = 1; //允许中断
IE0 = 0; //清除中断标志位
void INT0_Isr(void) interrupt 0// 中断触发后执行的函数
{
SEG0 += 1; //数码管0的数值+1
}
Rain_Personal
发表于 2024-4-27 15:15:33
第十六课IO中断
IO中断于Pin的中断区别,中断里面不能添加延时函数。
Rain_Personal
发表于 2024-4-27 17:24:00
zhaoye818 发表于 2024-4-27 15:56
学习真认真
谢谢,非科班出身,只能死磕{:4_167:},共同进步
Rain_Personal
发表于 2024-4-27 18:02:20
本帖最后由 Rain_Personal 于 2024-4-28 18:17 编辑
第十七课模数转换器ADC
1. ADC原理
个人理解有点像递归调用,
使用ADC功能时,Vref引脚的单片机不能悬空,必须接外部参考电压源或者VCC!!! 是不是表明如果不接Vref就会烧毁单片机?
实验箱的采用的是2.5V基准电压
ADC接口需要设置为高阻输入相当于初始化ADC
P1M0 = 0x00; //设置P10为高阻输入
P1M1 = 0x01;
ADCTIM = 0X3F; //ADC内部时序
ADCCFG = 0X2F; //数据右对齐,时钟选择位SYSCLK/2/16最慢
ADC_POWER = 1; //打开adc电源
u16ADC_Read( u8 no )// no 表示通道
{
u16 adcval; //adc数值保存变量
ADC_CONTR &= 0xf0; //清空通道
ADC_CONTR |= no; //选择通道
ADC_START = 1; //开启ADC转化
_nop_(); //空操作指令 intrins.h
_nop_();
while(!ADC_FLAG); //等待ADC转换结束
ADC_FLAG = 0;
adcval = (ADC_RES << 8)+ ADC_RESL; //计算adc的数值高8位 低8位用两个16进制描述12位的ADC值
adc_val = adcval;
return adcval;
}
通道的选择 其中ADC_CHS表示通道,函数调用需要输入对应参数 0000~0111即0~7
实验箱中可以通过按键生成ADC值
SW1~SW16
获取真实电压值的计算方式为
u16 ADC_CAL_Voltage(u16 num)
{
return num*2.5*1000 /4096; // num取值为0-4096 返回值为0-2500
}