soso_lxy 发表于 2011-1-17 01:00:28

新手作业——1602+DS3231+STC89C53简单时钟+第一次制作PCB。。。。

学51也好几个月了。。。。。做了不少时钟。。。。。。。但都是洞洞板或者用别人现成的板子。。。。。。。

刚好手电有人做1602,想开板,偶也来尝试一下。。。。。。。。。。

第一次做PCB,不敢弄太复杂的,软件还没熟悉呢。。。。。1602最适合练手了。。。。。。

貌似大家都是用DS1302做时钟,不过时间不准太头痛了。。。。。。。。我费了九牛二虎之力才把其中几个DS1302时钟调的误差很小(几天1秒吧),但是在太折腾了。。。。还是一步到位用DS3231 RTC吧。。。。。如果要求不高,还省了DS18B20,直接用DS3231内置温度传感器了(虽然官方指标±3°,但作为日常参考温度,也够用了)。。。。。

单片机——最通用的AT89S52或者STC89C52。。。。。。。。。。。。
5V MINIUSB口供电(可选5mm圆孔插头)。。。。。。。。。。。。。
大概流程图如下,没几个零件,感觉超级简单。。。。。。。。。。。。
http://cache.amobbs.com/bbs_upload782111/files_35/ourdev_611580YNUL5W.jpg
(原文件名:1602+DS3231SCH.jpg)

不过学化学的我,电子基础约等于0,虽然很简单的东西,等真正要画图的时候晕了。。。。。。。。。。
貌似很多人还在用Protell99,我也跟风学这个。。。。。。。但这个系统的操作,简直就是WIN32年代的东西。。。。。忍受不了。。。
改换门庭,一次到位,学AD9。。。。。。。。这下倒好,自己给自己找麻烦。。。。。。软件实在太专业了,不知从哪儿入手。。。。。。
在最后拼着一股牛劲,以很不成熟的方式,连流程图都没对应好,拼着出来一个单面PCB。。。。。。。。。部分电容电阻直插贴片兼容。。。
http://cache.amobbs.com/bbs_upload782111/files_35/ourdev_611581QYSYBZ.jpg
(原文件名:1602+DS3231.jpg)

不管了,打样去。。。。。。。等啊等啊。。。。。。。N天后拿到了我的第一块板子。。。。。。。
嘿嘿,貌似还能用。。。。。。。虽然有几个小错误。。。。。。。。(5mm圆孔插头的过孔小了,不知道厂家的问题还是我的问题,我PCB图上过孔貌似很大的。。。。。只能剪剪脚再安装5mm电源座了,不过MINIUSB的很好,没事就用这个吧)。。。。。。另外另外,就是几个电容,应该转个90度,这样就更方便了。。。。。。。
http://cache.amobbs.com/bbs_upload782111/files_35/ourdev_611596K2MCCI.jpg
(原文件名:N70_2456.jpg)

板子都到了,开干,焊上需要的零件。。。。。。差不多成型了。。。。。。。
正反面的样子,哈哈,还好还好。。。。。。。。。
http://cache.amobbs.com/bbs_upload782111/files_35/ourdev_611597T14VA4.JPG
(原文件名:N20_0012.JPG)
http://cache.amobbs.com/bbs_upload782111/files_35/ourdev_611598LN0H9F.jpg
(原文件名:N70_2461.jpg)

焊接完毕。。。。。。。剩下就是程序了。。。。。。。。。
1602的简单,但DS3231 I2C的方式还没学过。。。。。。。虽然有官方例程,但貌似有点乱。。。。。。。
开始听WANG1JIN的I2C课程,讲24C08的。。。。。貌似不难,照抄到我的DS3231上。。。。
但结果是杯具的。。。。。。。读出一堆问号或者I5。。。。。
找网上例程,用51的很少,基本都是用AVR的。。。。。。移植。。。。。。。还是杯具。。。。。
莫非硬件?该死。。。。。。硬件全是有问题。。。。。本来左上4脚(也就是13脚该接地的),怎么把左下4脚接地了。。。。
妈妈咪呀,当时没找到DS3231的封装,自己做的,真出问题了。。。。。。把RST接地了,GND悬空,DS3231能干活吗。。。。。真实。。。
做个小手术。。。。。。4脚悬空,13脚接地。。。。。但还是杯具。。。。。。。。。。。。。。结果一样。。。。。。。
担心IC被我整坏了,换一个,继续杯具。。。。。。。。
SCL SDA上拉10K,莫非太小,换4.7K。。。。。杯具。。。。。
不用DS1302,用个DS3231,自寻烦恼啊。。。。。。。。。。。
百度啊百度。。。。。。网上终于有个51的例程照抄还是杯具的。。。。。。
手上没有示波器,没有逻辑分析仪,看不到I2C的时序。。。。。。。。苦恼。。。。。。
延时已经改了又改。。。。。。偶然想起读取温度寄存器不能连续,读取时间跟读取温度寄存器过程延时时间长一点试试。。。。。
两次读取过程加了个400ms延时。。。。。。。。。晕,居然通了。。。。。。。。。。。。。
难看DS3231读取间隔要延时这么长,不会吧。。。。。。。。。。。。。。再试不同的延时方式。。。。。。。
再也没有成功。。。。。。。。。。。。。。。。。。。。。。。。
板子没做ISP下载,用AT89S52,AT89C52做的测试,每次插拔芯片,辛苦死了。。。。。。。
干脆在IC座引脚上焊两根线,用STC的在线烧录做测试,省得每次插拔芯片。。。。。。。。。
结果。。。。。。。。。。。。。。。换上一片STC89C53,居然读出时间了。。。。。。。每次读取延时怎么弄都成。。。。。。。
I2C时序稍微调整一下也没事。。。。。。。。。。。。。。。。。。。
我的天哪。。。。。。。。。。。别把我当作STC枪手啊。。。。。。。。这是我的实际经历。。。。。。。
I2C总线我接的P17 P16,为啥这样。。。。。。。。。。等高手的解答。。。。。。。。。。。。
终于调通了。。。。。。上个图先。。。。。。。。。。。。。。。。。
http://cache.amobbs.com/bbs_upload782111/files_35/ourdev_611599FFJVEI.jpg
(原文件名:N70_2466.jpg)

简单的菜单。。。。。。。
http://cache.amobbs.com/bbs_upload782111/files_35/ourdev_611600WRT0XG.jpg
(原文件名:N70_2463.jpg)

完善程序。。。。。。。按键。。。。两个独立闹钟。。。。,自动星期。。。。。。菜单返回。。。。。。。
音乐铃声还在杯具中。。。。。先预听吧。。。。。。
板上预留DS18B20接口(用延长线,离开发热的PCB,保证温度准确),加上DS18B20程序,但实际还没写完,需要用上的时候再加个显示小程序就行了,读取,判断都加上了。。。。
没有DS18B20用内置温度传感器,如果检测到有DS18B20,用18B20的数据。。。。。。。
差不多先这个样了。。。。。。。程序先放上来,请大家多多指点。。。。。。。

点击此处下载 ourdev_611582CDT6LL.rar(文件大小:133K) (原文件名:程序.rar)

不是科班出生。。。。。玩个小东西。。。。。真累啊。。。。。。。。
趴下休息ING。。。。。。。。。。。。。。。。。。。

chinapower0758 发表于 2011-1-17 01:49:40

很好新手做到这么好

renpeng009 发表于 2011-1-17 02:48:37

呵呵,支持!这种精神很好

llssr 发表于 2011-1-17 12:27:11

楼主那个电池什么型号?有资料吗?

kerrwang1982 发表于 2011-1-17 12:38:44

呵呵,厉害啊,不过开板太烧钱了,所以我现在还没有开过板,不过,最近准备DIY PCB。用过硫酸体系的腐蚀法。

soso_lxy 发表于 2011-1-17 18:25:07

回复【3楼】bbssr
楼主那个电池什么型号?有资料吗?
-----------------------------------------------------------------------

带焊脚的CR1220,淘宝很好找,不需要资料。。。。。。

soso_lxy 发表于 2011-1-17 18:26:41

回复【4楼】kerrwang1982
呵呵,厉害啊,不过开板太烧钱了,所以我现在还没有开过板,不过,最近准备diy pcb。用过硫酸体系的腐蚀法。
-----------------------------------------------------------------------


呵呵,找个便宜一点的厂家,其实开板很便宜的。。。。。。我这次做了20片,平均到每片5块不到吧。。。。。

yufan 发表于 2011-1-17 18:29:15

mark

yxzt 发表于 2011-1-17 19:41:07

话说去年申请了2片DS3231,却说搬了次家,就不翼而飞了,郁闷ing!

pxlpxlpxl 发表于 2011-1-17 21:11:01

楼主的PCB比我画得好,大面积敷铜是怎么做到的,我学的PROTEL 2.X好像没有这个功能。

muzheyun 发表于 2011-1-17 21:27:43

MARK.楼主,难道大面积铺铜不多花钱吗?我做的第一个PCB都没敢铺一点痛,

soso_lxy 发表于 2011-1-18 14:56:08

回复【9楼】pxlpxlpxl
楼主的pcb比我画得好,大面积敷铜是怎么做到的,我学的protel 2.x好像没有这个功能。
-----------------------------------------------------------------------
我后来用的AD9,PROTELL不知道怎么弄 了哈。。。。。

bbsview 发表于 2011-1-18 17:24:10

新手能做到如此也不错了,学电子就得实际动手,否则神马都是浮云!

soso_lxy 发表于 2011-1-19 11:34:33

回复【10楼】muzheyun
mark.楼主,难道大面积铺铜不多花钱吗?我做的第一个pcb都没敢铺一点痛,
-----------------------------------------------------------------------

呵呵,做PCB价格只跟尺寸,层数有关吧。。。。至于你铺多少铜,我想厂家不会在意的。。。。。。。。。

muzheyun 发表于 2011-1-19 11:42:59

早知道我就全都铺上了。

yanzeyuan 发表于 2011-2-1 23:37:32

竟然搜到你的帖子了,顶一下!

xunke 发表于 2011-2-21 23:32:24

回复【楼主位】soso_lxy
-----------------------------------------------------------------------

强!

CSU_David 发表于 2011-2-21 23:38:26

顶~

jrcsh 发表于 2011-2-22 00:35:51

这新手。。。。。PCB作得比我好~~~~ 哈哈

Jack_Lou 发表于 2011-2-22 10:07:30

楼主能不能加上个电波种接收模块,这样就省的对时了。

xunke 发表于 2011-2-22 10:24:44

回复【楼主位】soso_lxy
-----------------------------------------------------------------------

能否提供:1602、5V、 MINIUSB口供电 的封装?
我的Q:448254938

xunke 发表于 2011-2-22 11:15:17

1602能显示 " ° "符号。

longriver05 发表于 2011-3-28 12:46:54

楼主也是学化学的啊,同行啊

mige062 发表于 2011-4-3 14:44:45

楼主的这个程序已经超过8K了,AT89S52能烧进去?我用STC89c52试了一下,装不下

mige062 发表于 2011-4-3 15:05:53

我调DS3231,如同楼主刚开始一样,各种悲剧,从MSP430单片机,换成STC89C52,都不行。
郁闷了好长时间。
程序怎么看都是对的。
电路没毛病,
后来,在程序没改的情况下,用手把电源线多插拔了几次,居然好使了,不知道什么原因。

xiaolei0428 发表于 2011-4-3 16:40:22

mark

woodlynn 发表于 2011-4-16 23:02:09

Mark下,下不了代码,标记一下。

ERDTxiduoduo 发表于 2011-4-17 14:09:59

mark

chishangpiao 发表于 2011-4-17 14:18:34

不错

lrbdh 发表于 2011-4-18 09:23:29

楼主很强啊!

326309158 发表于 2011-4-18 10:04:29

楼主,PCB花了how much???

326309158 发表于 2011-4-18 10:05:51

近来想自己搞块板板的,but看到那价格,就有点怕...

babysnail 发表于 2011-4-18 10:10:29

那排针很强大!!!!

grc0709 发表于 2011-7-28 18:47:03

mark下

wb5846410 发表于 2011-7-31 06:40:53

23楼长了一个大猪头,楼主明明写着1602+DS3231+STC89C53,你偏偏要用s52.

longwu911 发表于 2011-7-31 13:01:48

哪个厂家制的板,我也想去做几块

785418837 发表于 2011-7-31 16:20:39

我头一次听说,官方的例程有点乱的。。嘿嘿

ICANDO 发表于 2011-7-31 19:35:12

很给力,哈哈

electron_love 发表于 2011-7-31 19:43:32

经过鉴定 发现lz是有钱淫

pkjapan 发表于 2011-7-31 19:54:41

楼主的话里面全是泡泡

lionliu 发表于 2011-11-4 18:03:32

记号下

Pony279 发表于 2011-11-4 18:27:40

不错~

咋这么多句号呀。。。。。。。。。。。。。。。。。。。。。。。。。。。

Pony279 发表于 2011-11-4 18:33:00

楼主你那个PCB打样得多少钱呀?

Pony279 发表于 2011-11-4 19:03:17

楼主看天祥的教程吧?有个地方我怀疑你被误导了,我一直在怀疑这个问题,今天在你的程序里看见了这个,所以特的验证了一下:
void delay()
{
       ;;
}
你的这个函数里的 ;; 是不起作用的,编译的时候会被自动忽略
口说无凭,看看这个函数的反汇编代码(KEIL 0级优化)吧
        RSEG?PR?delay?MAIN
delay:
        USING        0
                        ; SOURCE LINE # 11
; {
                        ; SOURCE LINE # 12
;        ;;
; }
                        ; SOURCE LINE # 14
?C0004:
        RET       
; END OF delay

        END

汇编代码里的 ; 号就是注释,END是伪指令,类似注释的东西,告诉编译器函数块到这里就结束了

这下明白了吧?整个函数只执行一条指令, RET,就是return


如果你还不相信,你可以反汇编调试一下,看到底执行了哪几句,我这里顺便贴上来

代码就这点
void delay()
{
       ;;
}

void main()
{       
        delay();
        while(1);
}

反汇编调试, 我在执行了的语句后加标号,(1) 表示第1个执行的指令,(2)表示第2个...

; .\main.SRC generated from: main.c
; COMPILER INVOKED BY:
;      D:\Program Files\Keil\C51\BIN\C51.EXE main.c OMF2 OPTIMIZE(0,SPEED) BROWSE INCDIR(..\..\INC;..\..\8051codelib\INC) DEBUG SRC(.\main.SRC)


NAME        MAIN

?PR?delay?MAIN       SEGMENT CODE
?PR?main?MAIN      SEGMENT CODE
        EXTRN        CODE (?C_STARTUP)
        PUBLIC        main
        PUBLIC        delay
; void delay()

        RSEG?PR?delay?MAIN
delay:
        USING        0
                        ; SOURCE LINE # 1
; {
                        ; SOURCE LINE # 2
;        ;;
; }
                        ; SOURCE LINE # 4
?C0001:
        RET       
; END OF delay

;
; void main()

        RSEG?PR?main?MAIN
main:
        USING        0
                        ; SOURCE LINE # 6
; {       
                        ; SOURCE LINE # 7
;         delay();
                        ; SOURCE LINE # 8
        LCALL        delay    ;--------------------------------------------------------------------(1)
?C0002:
;         while(1);            
                        ; SOURCE LINE # 9
        SJMP         ?C0002   ;--------------------------------------------------------------------(3, 4, ...,死循环)

?C0003:
; }
                        ; SOURCE LINE # 10
?C0004:
        RET    ;--------------------------------------------------------------------(2)       
; END OF main

        END


要说这个函数真的有延时,那也对,
因为调用函数基本上都有执行LCALL(函数调用的指令)和RET(返回指令,就相当于return;),这里就有几个机器周期了(对51的汇编不熟,具体多少时间我也不清楚)

感谢楼主开源~以后在论坛里多多交流~./emotion/em012.gif

Pony279 发表于 2011-11-4 19:11:37

另外再给楼主个建议
按键扫描最好不要软件Delay,用状态机
我也是菜鸟,前段时间里看见论坛里有人讨论这个问题,所以特地去了解了一下,原理还是挺简单的

楼主可以去看 马潮 编的书
http://ishare.iask.sina.com.cn/f/8882764.html
印象中貌似是第9章吧。。。(AVR我也没学过。。。看他的程序的构思就行了,很简单的)

vvooo2009 发表于 2011-11-4 20:53:16

回复【楼主位】soso_lxy
-----------------------------------------------------------------------

呵呵。。我以前先用面包板弄下,再pcb.

iamgo 发表于 2011-11-5 16:16:13

做个记号,楼主继续努力

pengda 发表于 2012-2-6 21:03:29

牛B啊!

yourhia 发表于 2012-2-6 23:49:17

PCB画得这么好还是第一次呢,LZ太谦了

youjianbaba 发表于 2012-4-2 21:40:00

本帖最后由 youjianbaba 于 2012-4-2 21:43 编辑

楼主,我做了一块与你一样的板子,用的相同器件,单只截取你的3231部分,但无法读取时间?
#include <STC89.h>
#include <intrins.h>

#define uchar unsigned char
#define uint unsigned int
/********1602定义***********************/
#define LCD_DB P0
sbit LCD_RS=P2^1;//0为指令,1为写数据
sbit LCD_RW=P2^2;//0可写入,1为读
sbit LCD_E=P2^5;//1允许

/*******ds3231相关定义*********/

/**************************** defines *******************************/
sbit    SCL = P1^7;             /* I2C pin definitions */
sbit    SDA = P1^6;
sbit    int0 = P3^2;
sbit    rest = P3^6;

#define ADDRTW0xD0    //器件写地址
#define ADDRTD0xD1        //器件读地址
//#define DS3231_WriteAddress 0xD0    //器件写地址
//#define DS3231_ReadAddress0xD1    //器件读地址

#define DS3231_SEC        0x00    //秒
#define DS3231_MIN        0x01    //分
#define DS3231_HOUR        0x02    //时
#define DS3231_DAY        0x03    //星期
#define DS3231_DATE        0x04    //日
#define DS3231_MONTH    0x05    //月
#define DS3231_YEAR        0x06    //年
//闹铃1            
#define DS3231_Al1SEC        0x07    //秒
#define DS3231_AL1MIN        0x08    //分
#define DS3231_AL1HOUR        0x09    //时
#define DS3231_AL1DAY        0x0A    //星期/日
//闹铃2
#define DS3231_AL2MIN        0x0b    //分
#define DS3231_AL2HOUR        0x0c    //时
#define DS3231_AL2DAY        0x0d    //星期/日
#define DS3231_CONTROL        0x0e    //控制寄存器
#define DS3231_STATUS        0x0f    //状态寄存器


#define BSY             2       //忙
#define OSF             7       //振荡器停止标志
#define DS3231_XTAL   0x10    //晶体老化寄存器
#define DS3231_TEMP_H        0x11    //温度寄存器高字节(8位)
#define DS3231_TEMP_L        0x12    //温度寄存器低字节(高2位)

//extern xdata uchar   sec, min, hour, day, date, month, year,Dtemp;
//extern xdata uchar al1_min,al1_hour,al1_day,al2_min,al2_hour,al2_day;
uchar year,month,date,day,hour,min,sec,Dtemp=0;
uchar al1_min,al1_hour,al1_day,al2_min,al2_hour,al2_day;

/*********************** Function Prototypes **************************/
uchar        BCD2HEX(uchar val);
uchar        B_BCD(uchar val);
void        delayus(uchar i);
void    Start();
void    Stop();
void        I2CACK(bit a);
void        SendByte(uchar Dat);
uchar        ReceiveByte(uchar b);
uchar        I2CWrite(uchar addr,uchar bytedata);
uchar        I2CRead();
uchar        I2CReadAdd(uchar addr);
void    read_temp();
void    init_alrm();
void        Readtime();
void        ReadAlarm();
void        SetTime(uchar yea,uchar mon,uchar da,uchar hou,uchar min,uchar sec);
void        InitDS3231();
bit                runnian();
void        autoweek();

bit ack;

uchar qushi;

/*******按键定义******/
sbit KEY= P3^2;


void InitTimer0(void);
//要在哪行那位显示啥就修改a和b
uchar idata c[]="ABCDEFGHIJKLMNOP";//显示字符串,一行最多16个字母
uchar idata d[]="0123456789abcdef";
uchar idata num="0123456789";//数字表
uchar a="2000-00-00 Day 0";//显示字符串,一行最多16个字母
uchar b="00-00-0000C   ";
   //////////"0123456789123456";

/******定义函数****************/


#define Busy 0x80 //DB7为1时表示忙,为0时表示闲
#define SomeNOP(); { _nop_(); }//空函数,用于微小延时,包含在intrins.h


void LCD_init(void);//初始化函数
void WaitForEnable( void );
void LCD_write_command(uchar dat,uchar AttribC);//写指令函数
void LCD_write_data(uchar dat);//写数据函数
void LCD_disp_addw(uchar x,uchar y,uchar dat);//在某个屏幕位置上显示一个字符,X(0-16),y(1-2)
void LCD_disp_lin(uchar x,uchar y,uchar dat[],uchar s);

void Delay5Ms(void);//延时函数
//********************************
//*******初始化函数***************
void LCD_init(void)
{
LCD_write_command(0x38,0);//设置8位格式,2行,5x7
Delay5Ms();
LCD_write_command(0x38,0);//设置8位格式,2行,5x7
Delay5Ms();
LCD_write_command(0x38,0);//设置8位格式,2行,5x7
Delay5Ms();
LCD_write_command(0x38,1);//设置8位格式,2行,5x7
LCD_write_command(0x08,1);// 显示关闭
LCD_write_command(0x01,1);//清除屏幕显示
LCD_write_command(0x06,1);//设定输入方式,增量不移位
LCD_write_command(0x0c,1);//整体显示,无光标,闪烁,0x0c
Delay5Ms();
}


/*=======================================================
正常读写操作之前必须检测LCD控制器状态: CS=1 RS=0 RW=1
DB7: 0 LCD控制器空闲; 1 LCD控制器忙---忙信号检测函数
========================================================*/
void WaitForEnable( void )//测忙函数
{
LCD_DB=0xff;
LCD_RS=0;
LCD_RW=1;
SomeNOP();
LCD_E=1;
SomeNOP();
SomeNOP();
while(LCD_DB&Busy);
LCD_E=0;
}

//********************************
//********写指令函数************
void LCD_write_command(uchar dat,uchar AttribC)
{
if (AttribC) WaitForEnable(); // 检测忙信号
LCD_DB=dat;
LCD_RS=0;//指令
LCD_RW=0;//写入
LCD_E=1;//允许
SomeNOP();
LCD_E=0;
Delay5Ms();
}
//*******************************
//********写数据函数*************
void LCD_write_data(uchar dat)
{
LCD_DB=dat;
LCD_RS=1;//数据
LCD_RW=0;//写入
LCD_E=1;//允许
SomeNOP();
LCD_E=0;
Delay5Ms();
}
//********************************
//**指定显示位置******************
void LCD_disp_addw(uchar x,uchar y,uchar dat)
{
uchar address;
if(y==1)
address=0x80+x;//第一行
if(y==2)
address=0xc0+x;//第二行
LCD_write_command(address,0);
LCD_write_data(dat);
}

//********************************
//*******显示多个字符函数或向任意行的任意位置写任意个字符,但位置不能超过16个*********
//x表示开始位置,第一位为1;y表示行数;dat[]是要显示的内容;s表示内容的长度,最大16
void LCD_disp_lin(uchar x,uchar y,uchar dat[],uchar s)
{
uchar ss;            
if(s>16||x>16)return;//各种情况下保证不超过16位
x=x-1;//为了符合自然习惯,在调用本函数是1代表末一行的第一位
if(s+x>16)return;//各种情况下保证不超过16位

for(ss=0;ss<s;ss++)
{
   LCD_disp_addw(x++,y,dat);//指向每个字符,一个一个的写,x轴自动加1,y表示行
}
}

// 短延时
void Delay5Ms(void)
{uchar w,i,j;   
for(w=5;w>0;w--)
for(i=2;i>0;i--)
for(j=255;j>0;j--);
}



/************************************************************/

/**********开始3231***********/
uchar BCD2HEX(uchar val)   //BCD转换为Byte
{
uchar i;
    i= val&0x0f;
    val >>= 4;
    val &= 0x0f;
    val *= 10;
    i += val;
   
    return i;
}

uchar B_BCD(uchar val)//B码转换为BCD码
{
uchar i,j,k;

i=val/10;
j=val%10;
k=j+(i<<4);
return k;
}

void delayus(uchar i)
{
   while(--i) ;
}
/************************START***************************/
void Start()
{
    SDA=1;                  //发送起始条件的数据信号
    delayus(1);
    SCL=1;
    delayus(5);             //起始条件建立时间大于4.7us,延时
   
    SDA=0;                  //发送起始信号
    delayus(5);             // 起始条件锁定时间大于4μs
      
    SCL=0;                  //钳住I2C总线,准备发送或接收数据
    delayus(2);
}
/********************************************************/
/************************STOP****************************/
void Stop()
{
    SDA=0;                  //发送结束条件的数据信号
    delayus(1);             //发送结束条件的时钟信号
    SCL=1;                  //结束条件建立时间大于4us
    delayus(5);
   
    SDA=1;                  //发送I2C总线结束信号
    delayus(4);
}
/********************************************************/
/*******************************************************************
                  字节数据发送函数               
函数原型:   void   SendByte(uchar Dat);
功能:      将数据c发送出去,可以是地址,也可以是数据,发完后等待应答,并对
         此状态位进行操作.(不应答或非应答都使ack=0)
         ack=1      发送数据正常,
         ack=0      被控器无应答或损坏。
********************************************************************/
void SendByte(uchar Dat)
{
uchar BitCnt;
   
    for(BitCnt=0;BitCnt<8;BitCnt++)         //要传送的数据长度为8位
    {
      if((Dat<<BitCnt)&0x80)
            SDA=1;                        //判断发送位
      else
            SDA=0;               
          delayus(1);
          SCL=1;                            //置时钟线为高,通知被控器开始接收数据位
          delayus(5);                     //保证时钟高电平周期大于4μs   
          SCL=0;
    }
   
    delayus(2);
    SDA=1;                                  //8位发送完后释放数据线,准备接收应答位
    delayus(2);
    SCL=1;
    delayus(3);
    if(SDA==1)
      ack=0;   
    else
      ack=1;                              //判断是否接收到应答信号
    SCL=0;
    delayus(2);
}
/********************************************************/
/*******************************************************************
                  字节数据接收函数               
函数原型:   uchar   RcvByte();
功能:      用来接收从器件传来的数据,并判断总线错误(不发应答信号),
         发完后请用应答函数应答从机。
********************************************************************/
uchar RcvByte()
{
uchar retc;
uchar BitCnt;

   retc=0;
   SDA=1;                           //置数据线为输入方式
   for(BitCnt=0;BitCnt<8;BitCnt++)
   {
      delayus(1);
      SCL=0;                      //置时钟线为低,准备接收数据位
      
      delayus(5);               //时钟低电平周期大于4.7μs
      
      SCL=1;                      //置时钟线为高使数据线上数据有效
      delayus(3);
      retc=retc<<1;
      if(SDA==1)
            retc=retc+1;            //读数据位,接收的数据位放入retc中
      delayus(2);
   }
   SCL=0;
   delayus(2);
   return(retc);
}
/********************************************************************
                      应答子函数
函数原型:   void I2CACK(bit a);
功能:       主控器进行应答信号(可以是应答或非应答信号,由位参数a决定)
********************************************************************/
void I2CACK(bit a)
{

    if(a==0)
      SDA=0;            //在此发出应答或非应答信号
    else
      SDA=1;
    delayus(3);   
    SCL=1;
   
    delayus(5);             //时钟低电平周期大于4μs
   
    SCL=0;                  //清时钟线,钳住I2C总线以便继续接收
    delayus(2);   
}
/****************************************************/
/***********将一个字节写入DS3231指定的地址***********/
uchar I2CWrite(uchar addr,uchar bytedata)
{
        Start();
    SendByte(ADDRTW);
    if (ack == 0)
      return 0;
   
    SendByte(addr);   
    if (ack == 0)
      return 0;
   
    SendByte(bytedata);
    if (ack == 0)
      return 0;
   
    Stop();
    delayus(10);      
    return 1;
}
/****************************************************/
/************从DS3231当前地址读一个字节************/
uchar I2CRead()
{
uchar read_data;

    Start();
    SendByte(ADDRTD);
    if(ack==0)
    {
                LCD_disp_addw(11,1,'t');/////
                return(0);
           }       
    read_data = RcvByte();
    I2CACK(1);
    Stop();
    return read_data;
}

/****************************************************/
/************从DS3231指定地址读一个字节************/
uchar I2CReadAdd(uchar addr)
{
    Start();
    SendByte(ADDRTD);
    if(ack==0)
    {
                LCD_disp_addw(12,1,'x');/////老是这里通不过                return(0);
           }       
    SendByte(addr);
    if(ack==0)
    {
                LCD_disp_addw(13,1,'y');
                return(0);
           }       
    return(I2CRead());
}
/***************************************************/
/*********************读取时间**********************/
void Readtime()
{
uchar temp;

temp=I2CReadAdd(DS3231_SEC);//秒
sec=BCD2HEX(temp);
temp=I2CReadAdd(DS3231_MIN);//分
min=BCD2HEX(temp);
temp=I2CReadAdd(DS3231_HOUR);//时
//temp&=0x3F;
hour=BCD2HEX(temp);
day=I2CReadAdd(DS3231_DAY);//星期
temp=I2CReadAdd(DS3231_DATE);//日
date=BCD2HEX(temp);
temp=I2CReadAdd(DS3231_MONTH); //月
month=BCD2HEX(temp);
temp=I2CReadAdd(DS3231_YEAR);//年
year=BCD2HEX(temp);
Dtemp=I2CReadAdd(DS3231_TEMP_H);//温度
}
/***************************************************/
/*******************读取闹铃时间********************/
void ReadAlarm()
{
uchar temp;

temp=I2CReadAdd(DS3231_AL1MIN);//分
al1_min=BCD2HEX(temp);
temp=I2CReadAdd(DS3231_AL1HOUR);//时
al1_hour=BCD2HEX(temp);
temp=I2CReadAdd(DS3231_AL1DAY);//星期or日
al1_day=BCD2HEX(temp);
temp=I2CReadAdd(DS3231_AL2MIN);//分
al2_min=BCD2HEX(temp);
temp=I2CReadAdd(DS3231_AL2HOUR);//时
al2_hour=BCD2HEX(temp);
temp=I2CReadAdd(DS3231_AL2DAY);//星期or日
al2_day=BCD2HEX(temp);
}


bit runnian()//闰年判断
{
        if((year%4==0&&year%100!=0)||(year%100==0&&year%400==0))
        {
                return 1;
        }
        else
        {
                return 0;
        }


}

void autoweek()
{
        Readtime();
        if( month == 1 || month == 2 )
    {
      month += 12;
      if( year> 0 )
            year--;
      else
            year = 4;
    }
        day = (1+(( date + 2*month + 3*(month+1)/5 + year + year/4 ) %7));
        I2CWrite(DS3231_DAY,day);
}

void InitDS3231()
{
        SCL=1;
        delayus(5);
        SDA=1;
        delayus(5);
        I2CWrite(DS3231_AL1DAY,0x81);        //A1M4置位,时分秒匹配时闹钟响应
        I2CWrite(DS3231_AL2DAY,0x81);        //A2M4置位,时分匹配时闹钟响应
        I2CWrite(DS3231_CONTROL,0x04);        //中断允许,闹钟1和2关闭
        I2CWrite(DS3231_STATUS,0x00);        //32KHZ输出禁止,闹钟标志位清零
        //SetTime(11,1,14,8,10,0);
}



/**********3231函数结束******/

void TimeDisplay(uchar Dhour,uchar Dmin,uchar Dsec)
{
    b=num;      // 时十位
    b=num;      // 时个位
    b=num;         // 分十位
    b=num;         // 分个位
    b=num;         // 秒十位
    b=num;         // 秒个位
   
}

//uchar a[]="2000-00-00 Day 0";//显示字符串,一行最多16个字母
//uchar b[]="00-00-0000C   ";
////////////"0123456789123456";



void DateDisplay(uchar Dyear,uchar Dmonth,uchar Dday)
{
    a=num;      // 年十位
    a=num;      // 年个位
    a=num;       // 月十位
    a=num;       // 月个位
    a=num;         // 天十位
    a=num;         // 天个位
   
}


/*******定时器0*****/
void InitTimer0(void)//定时器0开,模式1,时长50ms
{
    EA = 1;
    TMOD = 0x01;       
    ET0 = 1;
    TH0 = 0x3C;
    TL0 = 0xB0;   
    TR0 = 1;
}


void Timer0Interrupt(void) interrupt 1
{
qushi=qushi+1;
if(qushi==8)//ds3231取时间隔400ms
   {
    qushi=0;
        Readtime();//显示时间

        Delay5Ms();
        Delay5Ms();
        Delay5Ms();
        DateDisplay(year,month,date);
        TimeDisplay(hour,min,sec);
//字符串显示
//函数原型void LCD_disp_lin(uchar x,uchar y,uchar dat[],uchar s)
//x表示开始位置,第一位为1;y表示行数;dat[]是要显示的内容;s表示内容的长度,最大16
    LCD_disp_lin(1,1,a,16);//从指定显示位置显示多个字符,这里指第1行第1位开始
    LCD_disp_lin(1,2,b,16);//从指定显示位置显示多个字符,这里指第2行第1位开始
    Delay5Ms();
   }
//在任意行的任意位置单个字母显示,原始函数,直接调用LCD_disp_addw,可以不用啦
//LCD_disp_addw(0,1,'V');//从指定显示位置显示一个字符,这里指第1行第1位,每行最多16个字符
//LCD_disp_addw(0,2,'Q');//从指定显示位置显示一个字符,这里指第2行第1位
   
       
       TR0 = 0;//重新装定定时器0
       TH0 = 0x3C;
   TL0 = 0xB0;
       TR0 = 1;
}

//*********主函数*****************
void main(void)
{

LCD_init();//初始化
LCD_disp_lin(1,1,c,16);//从指定显示位置显示多个字符,这里指第1行第1位开始
LCD_disp_lin(1,2,d,16);//从指定显示位置显示多个字符,这里指第2行第1位开始
Delay5Ms();
Delay5Ms();
Delay5Ms();
rest=0;
InitDS3231(); //初始化DS3231
autoweek(); //开机自动星期转换

Delay5Ms();
Delay5Ms();
Delay5Ms();

qushi=0;                                    
InitTimer0();//定时器0开,模式1,时长50ms

while(1);
}

youxun 发表于 2012-4-10 12:43:46

楼主强!

hxzjackson 发表于 2012-4-10 13:02:41

学化学的也来抢我们饭碗了,呵呵

songzhe666 发表于 2013-8-15 10:47:22

{:biggrin:}多谢分享

kerrwang1982 发表于 2013-12-7 18:49:08

mige062 发表于 2011-4-3 15:05
我调DS3231,如同楼主刚开始一样,各种悲剧,从MSP430单片机,换成STC89C52,都不行。
郁闷了好长时间。
程 ...

用ATMEGA16没搞定,结果用AT89S52一调就通了。郁闷了半天。

kerrwang1982 发表于 2013-12-7 18:51:05

wb5846410 发表于 2011-7-31 06:40
23楼长了一个大猪头,楼主明明写着1602+DS3231+STC89C53,你偏偏要用s52.

楼主,开始用的S52,后天因为没有预留ISP,所以改用STC,这样不用来回插拔了。

kerrwang1982 发表于 2013-12-7 18:54:16

youjianbaba 发表于 2012-4-2 21:40
楼主,我做了一块与你一样的板子,用的相同器件,单只截取你的3231部分,但无法读取时间?
#include
#incl ...

换程序吧,我没用楼主的,

http://www.amobbs.com/forum.php?mod=viewthread&tid=5531595&pid=7171389&page=1&extra=#pid7171389

这个链接二楼的,用S52一调就通了。

shenming420 发表于 2014-9-29 13:44:45

下载楼主的程序参考下,我用STC单片机控制。。。

hustsolo 发表于 2014-10-10 19:27:24

这个必须顶!楼主好样的,话说,我也是业余做做【表情】

niepan 发表于 2014-10-15 17:17:45

能否发个PCB,偷个懒{:smile:}

fsj5098@hotmail 发表于 2015-5-14 19:53:31

支持lz的开源

fsj5098@hotmail 发表于 2015-5-24 12:11:12

我仿制了一个两个,一个用了stc89c52,一个用了stc12c5a60s2   stc12c5a60s2 不成功,stc89c52能运行,但是年月日字符是乱码,不知错在那

fsj5098@hotmail 发表于 2015-5-29 00:21:13

lz 我仿制为何有乱码
页: [1]
查看完整版本: 新手作业——1602+DS3231+STC89C53简单时钟+第一次制作PCB。。。。