找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 213|回复: 8
收起左侧

单片机电子钟调时问题

[复制链接]
ID:143767 发表于 2024-10-12 11:39 | 显示全部楼层 |阅读模式
这个程序是在网上找到的,硬件搭建完成后把程序烧录到单片机,电子钟从00:00开始走,但是按调节按钮后电子钟显示01:01,松开后又进入走时状态,不管是单击,双击,多击,或按住不放等待几秒后都是进入走时状态,不能调节时间,请大家帮忙看一下这程序有什么问题,谢谢

//下载时选择片内RC振荡12M
  1. #include <reg51.h>
  2. #define uchar unsigned char
  3. #define uint  unsigned int
  4. sbit din=P3^0; //引脚定义
  5.   sbit clk=P3^1;
  6. sbit sck=P3^2;
  7. sbit SDA=P3^3;
  8. sbit SCL=P3^4;
  9. sbit set=P3^5;
  10. bit ack; //应答位

  11. #define DS3231_WriteAddress 0xD0//器件写地址
  12. #define DS3231_ReadAddress  0xD1//器件读地址
  13. #define DS3231_SECOND  0x00//秒
  14. #define DS3231_MINUTE  0x01//分
  15. #define DS3231_HOUR      0x02//时
  16. #define DS3231_WEEK      0x03//星期
  17. #define DS3231_DAY      0x04//日
  18. #define DS3231_MONTH  0x05//月
  19. #define DS3231_YEAR      0x06//年
  20. //#define bcd_hex(bcd) ((((uchar)bcd) & 0xF0) >> 4) * 10 +  (((uchar)bcd) & 0x0F) //8421码转16进制
  21. //uchar bcd_hex(uchar bcd){return((bcd/16*10)+(bcd&0x0f));}
  22. //#define hex_bcd(hex) (((u8)hex) % 10) + ((((u8)hex) /10) << 4)//16进制转8421码

  23. void delayus(uint us) {while(--us);}
  24. void Start_I2C(void){SDA=1;delayus(1);SCL=1;delayus(5);SDA=0;delayus(5);SCL=0;delayus(2);} //I2C开始
  25. void Stop_I2C(void) {SDA=0;delayus(1);SCL=1;delayus(5);SDA=1;delayus(5);} //I2C停止
  26. void SendByte_595(uchar date); //74hc595发送字节时序
  27. void  SendByte_3231(uchar date); //ds3231发送字节时序
  28. uchar write_byte_3231(uchar addr,uchar write_date);//指定地址写入字节
  29. uchar RcvdByte_3231(void); //ds3231接收字节时序
  30. void  Ack_3231(bit a); // 发送应答与否
  31. uchar read_current(void);
  32. uchar read_random(uchar random_addr);
  33. // uchar date[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
  34. code uchar code_led[]={
  35. 0x40,  // 0
  36. 0x79,  // 1
  37. 0x24,  // 2
  38. 0x30,  // 3
  39. 0x19,  // 4
  40. 0x12,  // 5
  41. 0x02,  // 6  
  42. 0x78,  // 7
  43. 0x00,  // 8
  44. 0x10,  // 9
  45. 0x08,  // A
  46. 0x03,  // B
  47. 0x46,  // C
  48. 0x21,  // D
  49. 0x06,  // E
  50. 0x0E  // F   
  51.     //0x00
  52. };


  53. void main()
  54. {
  55. uint  d=0;//点闪计时
  56. uchar i;
  57. uchar miao,fen,shi,ri,yue,nian;   
  58. uchar w[4];
  59. //uchar n=20,y=10,r=3,s=14,f=16,m=31;//调整时间用
  60. while(1){
  61. ////////////////////////////

  62. d=d+1;
  63. if(d%1000==0)
  64. {
  65. if(miao!=read_random(DS3231_SECOND))
  66. {  
  67.    d=0;
  68.    miao =read_random(DS3231_SECOND);
  69.    fen  =read_random(DS3231_MINUTE);
  70.    shi =read_random(DS3231_HOUR);
  71.    ri  =read_random(DS3231_DAY);
  72.    yue =read_random(DS3231_MONTH);
  73.    nian =read_random(DS3231_YEAR);
  74.   
  75.    w[0]=code_led[shi/16];w[1]=code_led[shi%16];
  76.    w[2]=code_led[fen/16];w[3]=code_led[fen%16];
  77. //   w[0]=code_led[fen/16];w[1]=code_led[fen%16];  
  78. //   w[2]=code_led[miao/16];w[3]=code_led[miao%16];   
  79.    for (i=0; i<4; i++) SendByte_595(w[i]); sck=0;delayus(5);sck=1;delayus(5);
  80. }
  81. }
  82. if(d==26000)
  83. {
  84.   w[1]=code_led[shi%16]^0x80;
  85.   w[2]=code_led[fen/16]^0x80;
  86. //  w[0]=code_led[fen/16];w[1]=code_led[fen%16]^0x80;  
  87. //  w[2]=code_led[miao/16]^0x80;w[3]=code_led[miao%16];   
  88.   for (i=0; i<4; i++) SendByte_595(w[i]); sck=0;delayus(5);sck=1;delayus(5);
  89. }
  90. /////////////////////////////////////
  91.   
  92.    while(set==0)
  93.    {
  94. w[0]=code_led[yue/16];w[1]=code_led[yue%16];
  95.     w[2]=code_led[ri/16]^0x80;w[3]=code_led[ri%16];
  96. for (i=0; i<4; i++) SendByte_595(w[i]); sck=0;delayus(5);sck=1;delayus(5);

  97. //   write_byte_3231(DS3231_SECOND,m/10*16+m%10);
  98. //   write_byte_3231(DS3231_MINUTE,f/10*16+f%10);
  99. //   write_byte_3231(DS3231_HOUR,s/10*16+s%10);
  100. //   write_byte_3231(DS3231_DAY,r/10*16+r%10);
  101. //   write_byte_3231(DS3231_MONTH,y/10*16+y%10);
  102. //   write_byte_3231(DS3231_YEAR,n/10*16+n%10);
  103.      }
  104. }
  105. }
  106. void SendByte_595(uchar date){uchar i;for(i=0;i<8;i++){clk=0;delayus(2);date<<=1;din=CY;delayus(5);clk=1;delayus(5);}}//595移位输出
  107. void SendByte_3231(uchar date) //发送一个字节
  108. {
  109. uchar i;
  110. for (i=0;i<8;i++){date<<=1;SDA=CY;delayus(1);SCL=1;delayus(5);SCL=0;}
  111. delayus(2);SDA=1;delayus(2);SCL=1;delayus(3);//释放SDA 准备接收应答信号
  112. if(SDA==1)ack=0;else ack=1;    //检测应答信号
  113. SCL=0; delayus(2);
  114. }
  115. uchar RcvdByte_3231(void)//读取一个字节的数据
  116. {
  117.   uchar i;
  118.   uchar date=0;
  119.   SDA=1;
  120.   for(i=0;i<8;i++)
  121.   {
  122.    delayus(1);
  123.    SCL=0;delayus(5); SCL=1;delayus(3);
  124.    date=date<<1;
  125.    if(SDA==1)date+=1; delayus(2);
  126.    }
  127.   SCL=0;
  128.    delayus(2);
  129.    return(date);
  130. }

  131. void Ack_3231(bit a){if(a==0)SDA=0;else SDA=1; delayus(3);SCL=1;delayus(5);SCL=0;delayus(2);}  //发送应答与否

  132. // uchar write_byte_3231(uchar addr,uchar write_date)
  133. // {
  134. // Start_I2C();
  135. // SendByte_3231(DS3231_WriteAddress);//呼叫ds3231传送
  136. // if(ack==0)return 0;
  137. // SendByte_3231(addr);//送地址
  138. // if(ack==0)return 0;// 无应答退出
  139. // SendByte_3231(write_date);//送数据
  140. // if(ack==0)return 0;// 无应答退出
  141. // Stop_I2C();
  142. // delayus(10);
  143. // return 1;//  发送成功
  144. // }

  145. uchar read_current(void)
  146. {
  147. uchar read_date;
  148. Start_I2C();
  149. SendByte_3231(DS3231_ReadAddress);
  150. if(ack==0)return 0;// 无应答退出
  151. read_date=RcvdByte_3231();
  152. Ack_3231(1);//接收到一个字节数据后非应答
  153. Stop_I2C();
  154. return read_date;
  155. }

  156. uchar read_random(uchar random_addr)
  157. {
  158.   Start_I2C();
  159.   SendByte_3231(DS3231_WriteAddress);//呼叫ds3231传送
  160.   if(ack==0)return 0;// 无应答退出
  161.   SendByte_3231(random_addr);
  162.   if(ack==0)return 0;// 无应答退出
  163.   return (read_current());
  164. }
复制代码

电路图
屏幕截图 2024-10-12 113740.png
补充一下, 单片机用的是STC15L104W,我用的是STC15W104,网上查是可以直接代换的。


回复

使用道具 举报

ID:155811 发表于 2024-10-12 14:37 | 显示全部楼层
使用 状态变量,按动按钮时候,依次进入 调日时分,可以解决问题
回复

使用道具 举报

ID:556433 发表于 2024-10-12 15:26 | 显示全部楼层
你这程序都不是完整的啊,没实现调整时间的功能,而且最好增加一个状态变量,来判断当前是显示时间还是调整时间的模式。
回复

使用道具 举报

ID:143767 发表于 2024-10-12 18:11 | 显示全部楼层
这个状态变量怎么写呢
回复

使用道具 举报

ID:556433 发表于 2024-10-14 11:58 | 显示全部楼层
void main() {
    uchar mode = 0; // 0显示模式、1调时模式

    while (1) {

    if (set == 0) {
        mode = 1 - mode; // 切换模式
        delayus(1000); // 防抖
    }

    if (mode == 1) {
        // 在此处添加调整时间的逻辑
        // 比如按下其他按钮来增加/减少时间
    }
  }
}

回复

使用道具 举报

ID:143767 发表于 2024-10-16 10:50 | 显示全部楼层
尝试写了一下,没成功,整不明白了,求高人指点
回复

使用道具 举报

ID:161164 发表于 2024-10-16 14:19 | 显示全部楼层
dj3365191 发表于 2024-10-16 10:50
尝试写了一下,没成功,整不明白了,求高人指点

只有一个set按键是如何控制数值加减?
回复

使用道具 举报

ID:143767 发表于 2024-10-17 10:50 | 显示全部楼层
lkc8210 发表于 2024-10-16 14:19
只有一个set按键是如何控制数值加减?

是他原来就这样设定的,但在程序中不知哪里是写按键使用逻辑的地方
回复

使用道具 举报

ID:143767 发表于 2024-10-22 10:13 | 显示全部楼层
keyneko 发表于 2024-10-14 11:58
void main() {
    uchar mode = 0; // 0显示模式、1调时模式

怎样写调整时间的逻辑,没有其他按钮了,除非复用
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表