|  | 
          1楼
          巨大八爪鱼
          2017-2-21 18:08
          
          
            #include <at89x52.h>
 #define _BV(n) (1 << (n))
 
 sbit PL = P3^0; // 置数端
 sbit MR = P3^1; // 清零端
 sbit TCU = P3^2; // 进位端
 sbit TCD = P3^3; // 借位端
 sbit CPD = P3^4; // 倒计时端
 sbit CPU = P3^5; // 计时端
 
 unsigned char code seg8[] = {0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90};
 
 void delay(unsigned int n)
 {
 unsigned char i;
 while (n--)
 for (i = 0; i < 115; i++);
 }
 
 void LS193_Clear(void)
 {
 MR = 1;
 MR = 0;
 }
 
 unsigned char LS193_Read(void)
 {
 return (P1 & 0x0f); // 输出端接P1低4位
 }
 
 void LS193_Write(unsigned char dat)
 {
 P1 = ((dat & 0x0f) << 4) | 0x0f; // 置数输入端接P1高4位
 PL = 0;
 PL = 1;
 }
 
 // 进位、借位信号出现的时间很短
 // 这样的判断方法不可靠
 /*
 // 判断是否进位
 bit LS193_Carry(void)
 {
 TCU = 1;
 return (TCU == 0);
 }
 
 // 判断是否借位
 bit LS193_Borrow(void)
 {
 TCD = 1;
 return (TCD == 0);
 }
 */
 
 // 向上计数
 void LS193_Up(void)
 {
 CPU = 0;
 CPU = 1;
 }
 
 // 向下计数
 void LS193_Down(void)
 {
 CPD = 0;
 CPD = 1;
 }
 
 void seg_scan(void)
 {
 unsigned char i;
 unsigned char n = LS193_Read();
 for (i = 7; i >= 6; i--) // 扫描第7、6个数码管,从低位到高位
 {
 P2 = 0xff;
 P0 = seg8[n % 10];
 P2 = ~_BV(i);
 delay(5);
 n /= 10;
 }
 }
 
 int main(void)
 {
 unsigned char i, j;
 P1 = 0x0f;
 
 LS193_Clear(); // 上电先清零
 
 IT0 = 1; // 下降沿触发
 EX0 = 1;
 IT1 = 1;
 EX1 = 1;
 EA = 1;
 // 把外中断的触发方式改为低电平触发(ITx=0)也没有问题
 // 因为进位、借位信号持续的时间极短(相应的时钟为低电平时才会出现)
 
 while (1)
 {
 for (j = 0; j < 32; j++)
 {
 for (i = 0; i < 40; i++)
 seg_scan();
 LS193_Up();
 }
 
 for (j = 0; j < 32; j++)
 {
 for (i = 0; i < 40; i++)
 seg_scan();
 LS193_Down();
 }
 }
 }
 
 void et0(void) interrupt 0
 {
 LS193_Write(2); // 进位时预置数2
 }
 
 void et1(void) interrupt 2
 {
 LS193_Write(10); // 借位时预置数10
 }
 
 | 
    
      |  | 
          2楼
          巨大八爪鱼
          2017-2-21 18:09
          
          
            /* 延长进、借位信号持续时间的方法 *//* 副作用: 每次进/退位会产生一短一长两次脉冲, 且切换计数方向时计数值不变 */
 #include <at89x52.h>
 
 #define _BV(n) (1 << (n))
 
 // 清零端(14)恒接低电平, 通电时计数值为随机数
 sbit TCU = P1^0; // 进位端(12)
 sbit TCD = P1^1; // 借位端(13)
 sbit CPD = P1^2; // 倒计时端(4)
 sbit CPU = P1^3; // 计时端(5)
 
 unsigned char code seg8[] = {0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90};
 
 void delay(unsigned int n)
 {
 unsigned char i;
 while (n--)
 for (i = 0; i < 115; i++);
 }
 
 unsigned char LS193_Read(void)
 {
 P3 |= 0x0f;
 return (P3 & 0x0f); // 输出端接P3低4位
 }
 
 // 判断是否进位
 bit LS193_Carry(void)
 {
 TCU = 1;
 return (TCU == 0);
 }
 
 // 判断是否借位
 bit LS193_Borrow(void)
 {
 TCD = 1;
 return (TCD == 0);
 }
 
 // 向上计数
 void LS193_Up(void)
 {
 CPD = 1; // 使向下计数无效, 副作用: 会产生一次向下计数,使得最终本次数字没有变
 CPU = 0;
 CPU = 1; // 产生上升沿
 CPU = 0; // =0时进位信号才能长期保持
 }
 
 // 向下计数
 void LS193_Down(void)
 {
 CPU = 1; // 使向上计数无效, 副作用:会产生一次向上计数
 CPD = 0;
 CPD = 1; // 产生上升沿
 CPD = 0; // =0时借位信号才能长期保持
 }
 
 void seg_scan(void)
 {
 unsigned char i;
 unsigned char n = LS193_Read();
 for (i = 7; i >= 6; i--) // 扫描第7、6个数码管,从低位到高位
 {
 P2 = 0xff;
 P0 = seg8[n % 10];
 P2 = ~_BV(i);
 delay(5);
 n /= 10;
 }
 
 // 若有进位则显示小写c
 if (LS193_Carry())
 {
 P2 = 0xff;
 P0 = 0xa7;
 P2 = ~_BV(0);
 }
 delay(5);
 
 // 若有借位则显示小写b
 if (LS193_Borrow())
 {
 P2 = 0xff;
 P0 = 0x83;
 P2 = ~_BV(1);
 }
 delay(5);
 }
 
 int main(void)
 {
 unsigned char i, j;
 while (1)
 {
 // 正计时
 // 等于15时进位灯亮
 for (j = 0; j < 32; j++)
 {
 for (i = 0; i < 40; i++)
 seg_scan();
 LS193_Up();
 }
 
 // 倒计时
 // 等于0时借位灯亮
 for (j = 0; j < 32; j++)
 {
 for (i = 0; i < 40; i++)
 seg_scan();
 LS193_Down();
 }
 }
 }
 
 | 
    
      |  | 
          3楼
          巨大八爪鱼
          2017-2-21 20:09
          
          
            /* 脉冲产生个数测试 */#include <at89x52.h>
 
 #define _BV(n) (1 << (n))
 
 // 清零端(14)恒接低电平, 通电时计数值为随机数
 sbit TCU = P3^2; // 进位端(12), 外部中断0
 sbit TCD = P3^3; // 借位端(13), 外部中断1
 sbit CPD = P1^2; // 倒计时端(4)
 sbit CPU = P1^3; // 计时端(5)
 
 unsigned char code seg8[] = {0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90};
 unsigned char num = 0; // 下降沿个数
 
 void delay(unsigned int n)
 {
 unsigned char i;
 while (n--)
 for (i = 0; i < 115; i++);
 }
 
 unsigned char LS193_Read(void)
 {
 P1 |= 0xf0;
 return (P1 >> 4) & 0x0f; // 输出端接P1高4位
 }
 
 // 向上计数
 void LS193_Up(void)
 {
 CPD = 1; // 使向下计数无效, 副作用: 会产生一次向下计数,使得最终本次数字没有变
 CPU = 0;
 CPU = 1; // 产生上升沿
 CPU = 0; // =0时进位信号才能长期保持
 }
 
 // 向下计数
 void LS193_Down(void)
 {
 CPU = 1; // 使向上计数无效, 副作用:会产生一次向上计数
 CPD = 0;
 CPD = 1; // 产生上升沿
 CPD = 0; // =0时借位信号才能长期保持
 }
 
 void seg_scan(void)
 {
 char i;
 unsigned char n = LS193_Read();
 for (i = 7; i >= 6; i--) // 扫描第7、6个数码管,从低位到高位
 {
 P2 = 0xff;
 P0 = seg8[n % 10];
 P2 = ~_BV(i);
 delay(5);
 n /= 10;
 }
 
 n = num;
 for (i = 2; i >= 0; i--) // 扫描第2~0个数码管,从低位到高位
 {
 P2 = 0xff;
 P0 = seg8[n % 10];
 P2 = ~_BV(i);
 delay(5);
 n /= 10;
 }
 }
 
 int main(void)
 {
 unsigned char i, j;
 
 IT0 = 1;
 EX0 = 1;
 IT1 = 1;
 EX1 = 1;
 EA = 1;
 
 while (1)
 {
 // 正计时
 for (j = 0; j < 32; j++)
 {
 for (i = 0; i < 80; i++)
 seg_scan();
 LS193_Up();
 }
 
 // 倒计时
 for (j = 0; j < 32; j++)
 {
 for (i = 0; i < 80; i++)
 seg_scan();
 LS193_Down();
 }
 }
 }
 
 void et0(void) interrupt IE0_VECTOR
 {
 num++;
 }
 
 void et1(void) interrupt IE1_VECTOR
 {
 num += 10;
 }
 
 // 正计时时,从14到15, num+1,说明产生了一个下降沿
 // 倒计时时,从01到00,再到15,都要加10,num一共加了20, 说明产生了两个下降沿
 
 | 
    
      |  | 
          4楼
          巨大八爪鱼
          2017-2-22 09:05
              在第一个程序中,当计数值为14且为向上计数的时候,时钟CPU先置0后置1,也就是先下降沿后上升沿,最后计数值变成15。CPU=0时计数值为14,所以无进位信号。当从15跳变到0时,因为进位信号只会出现在CPU=0时,且此时计数值为15,所以产生进位信号。因为CPU=0持续的时间极短,大约只有一个时钟周期,所以进位信号有效的时间也极短。如果不使用中断的话基本上检测不出来。
 这大大提高了系统的可靠性,使得在置数的时候可以保证不出现计数值=0的情况,直接跳变至指定的数字。
 |