51日更 2
1.c中!和~区别
!是逻辑符号,对一个数据进行!运算时,必须先把该数据强制转换为Bool型,即0或1,再进行运算。(Bool型非0就是1)
而~是位运算,对任何数据都不需要强制转换,起作用是将数据在内存中的每一位(当然是二进制)取反。
两种运算的结果一般不相等。
2.KEIL警告
*** WARNING L1: UNRESOLVED EXTERNAL SYMBOL
SYMBOL: _DELAY
MODULE: .\Objects\9.18.obj (9_18)
*** WARNING L2: REFERENCE MADE TO UNRESOLVED EXTERNAL
原因:没把C文件添加到项目中!
另外,还有可能是因为存在没有被调用的已经定义的函数,或者相关的已经定义的变量没有使用。
9.18.c(8): error C100: unprintable character 0xA3 skipped
原因:符号用的全角字符,改成半角的,一般是‘;’打错了
9.18.c(8): error C202: ‘LED_Init0x01’: undefined identifier
检测‘()’是不是格式错误
*** WARNING L16: UNCALLED SEGMENT, IGNORED FOR OVERLAY PROCESS
SEGMENT: ?PR?_LED_RIGHT?LED
原因:该函数没有调用,屏蔽就好了
3.继电器控制
电路分析:开漏输出(降低功耗),当PNP导通DK亮(指示灯),并联反向接一个IN4148,目的在于稳压,防止反向电流击穿三极管和单片机,有两个接线端,NC1(normal close 1)常闭,NO1(normal open)常开,其余两个是COM端,将MP或NO串连到电路即可控制电路,当开关用,切记,该电路没有保护电路,不要尝试接高压。
5.51单片机的精确延时(软件延时)
电子中将脉冲信号之间的时间间隔称为周期,单位个;单位时间(如1秒)内所产生的脉冲个数称为频率,它的标准计量单位是Hz(赫)。
指令周期:CPU执行一条指令所需要的时间称为指令周期,它以机器周期为单位,不同的指令之间,所需要的机器周期也不同。如,取指令需要一个机器周期,转移指令2个打不住。
时钟周期:也称为振荡周期,一个时钟周期 = 晶振的倒数。它是单片机的基本时间单位,两个组成一个状态周期。
机器周期:单片机的基本操作周期,在一个操作周期内,单片机完成一项基本操作,如取指令、存储器读/写等。
一个机器周期=6个状态周期=12个时钟周期。
一个单周期指令包含一个机器周期,即12个时钟周期,所以一条单周期指令被执行所占时间为12*(1/ 晶振频率)= x μs。
TM1637芯片手册解读
意图:手上有个4位一体的时钟显示模块,利用的TM1637驱动。
TM1637 是一种带键盘扫描接口的LED(发光二极管显示器)驱动控制专用电路。
特性:显示模式(8 段×6 位),支持共阳数码管输出,两线串行接口(CLK,DIO)内置上电复位电路、内置自动消隐电路、振荡方式:内置RC 振荡(450KHz+)、辉度调节电路(占空比 8 级可调)
2)管脚说明:
功能定义:
DIO数据输入/输出17串行数据输入/输出
CLK时钟输入 18 在上升沿输入/输出数据
SG1~SG8 输出(段) 2-9 N 管开漏输出
GRID6~GRID1 输出(位) 10-15 P 管开漏输出
3)电路原理图:
GRID位选:选择控制哪个数码管
SEG 段选:控制数码管显示数字几
该寄存器存储通过串行接口从外部器件传送到TM1637 的数据,地址00H-05h共6个字节单元,分别与芯片SGE和GRID管脚所接的LED灯对应。
写LED显示数据的时候,按照从显示地址从低位到高位,从数据字节的低位到高位操作。
4)接口说明
通过两线总线接口和 TM1637 通信,在输入数据时当 CLK 是高电平时,DIO 上的信号必须保持不变;只有 CLK 上的时钟信号为低电平时,DIO 上的信号才能改变。数据输入的开始条件是 CLK 为高电平时,DIO 由高变低;结束条件是 CLK 为高时,DIO 由低电平变为高电平。
主要看PWCLK,时钟周期(振荡周期)最小400ns,两个时钟周期=一个状态周期
写SRAM两种模式
5)数据指令说明
指令用来设置显示模式和LED 驱动器的状态。
在CLK下降沿后由DIO输入的第一个字节作为一条指令。经过译码,取最高B7、B6两位比特位以区别不同的指令。
6)代码部分
可知有两种编程方式,下面是官方给的程序流程图
51下的代码解读:
参考http://m.elecfans.com/article/605149.html
感谢大神的整理分享!!!
//延时1ms
void Delay_1ms(unsigned int i)
{
unsigned char x,j;
for(j=0;j<i;j++)
for(x=0;x<=120;x++);
// 晶振为12MHZ时 把 x=120,晶振为11.0592MHZ时 把 x=110
}
//倒计时时间算法,检测是否到了一分钟相应的位减一
void time_judge( void )
{
if(++sec == 60) //60秒
{
sec = 0;
if((Hour.shi || Hour.ge || Min.shi || Min.ge) && (--Min.ge <= -1))
{
Min.ge = 9;
if((Hour.shi) ||(Hour.ge) && (--Min.shi <= -1))
{
Min.shi = 5;
if(Hour.shi && (--Hour.ge <= -1))
{
Hour.ge = 9;
if(--Hour.shi <= -1)
{
Hour.shi = 0;
}
}
else
if((!Hour.shi) && (--Hour.ge <= -1))
{
Hour.ge = 0;
}
}
else
if((!Hour.shi) && (!Hour.ge) && (--Min.shi <= -1))
{
Min.shi = 0;
}
}
else if(((!Hour.shi) && (!Hour.ge) && (!Min.shi) ) && (Min.ge <= -1))
{
Min.ge = 0;
}
}
}
//主函数:定时器0初始化
//循环部分:显示时间,半秒切换一次数码管第二位,用于判断/控制第二//个数码管的dp的显示,1s调用一次倒计时时间算法
void main( void )
{
timer0_init();
time_set(1, 0); //设置5小时倒计时
while(1)
{
time_display(); //显示时间
//1个countTime=0.005s ,
if(countTime <= 10) //10个countTime=0.5s
{
dpFlag = 0;
}
else if(countTime <= 20)//20个countTime1s=1s
{
dpFlag = 1;
}
else
{
countTime = 0; //countTime1s复位
time_judge();
}
}
}
//显示时间
void time_display( void )
{
TM1637_writeCammand(0x44);//0 1 数据命令设置,设置为固定模式,写数据到显示寄存器
TM1637_writeData(0xc0, SEGData[Hour.shi]);
//1 1 地址命令设置
if(dpFlag)
TM1637_writeData(0xc1, SEGDataDp[Hour.ge]); //小数点标志为1则用小数点那个数组
else
TM1637_writeData(0xc1, SEGData[Hour.ge]);
TM1637_writeData(0xc2, SEGData[Min.shi]);
TM1637_writeData(0xc3, SEGData[Min.ge]);
TM1637_writeCammand(0x8a); //1 0 显示控制命令设置 ,显示开,脉冲宽度1/4
}
//写指令
void TM1637_writeCammand(unsigned char mData)
{
TM1637_start();
TM1637_write1Byte(mData); //数据
TM1637_stop(); //结束函数,看时序图写的
}
//开始函数,看时序图写的
void TM1637_start( void )
{
CLK = 1;
DIO = 1;
delay_140us();
DIO = 0;
delay_140us();
CLK = 0;
delay_140us();
}
//写1byte
void TM1637_write1Byte(unsigned char mByte)
{
char loop = 0;
for(loop = 0; loop < 8; loop++)
{
TM1637_write1Bit((mByte>>loop)&0x01); //取得最低位
}
CLK = 0;
delay_140us();
DIO = 1;
delay_140us();
CLK = 1;
delay_140us();
while(DIO == 1); //获得应答位
}
//写一位
void TM1637_write1Bit(unsigned char mBit )
{
CLK = 0;
delay_140us();
if(mBit)
DIO = 1;
else
DIO = 0;
delay_140us();
CLK = 1;
delay_140us();
}
// 固定地址写数据1byte
void TM1637_writeData(unsigned char addr, unsigned char mData)
{
TM1637_start();
TM1637_write1Byte(addr); //地址 ,1 1 地址命令设置
TM1637_write1Byte(mData); //数据
TM1637_stop();
}
//以上代码编写需看懂时序图