找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 2140|回复: 7
打印 上一主题 下一主题
收起左侧

求助,根据ds1302得出的时间进行太阳追踪 单片机程序问题

[复制链接]
跳转到指定楼层
楼主
我想根据制作一个可以调节的ds1302时钟,再根据时钟计算出太阳高度角和方位角来进行太阳追踪

可是我的程序却不能用按键将改好的时间写入ds1302
有高手能看下哪里不正确需要改吗


单片机源程序如下:
  1. #include <REG52.h>
  2. #include <intrins.h>
  3. #include <math.h>

  4. #define uchar unsigned char
  5. #define uint  unsigned int
  6. #define PI 3.14159                        //圆周率
  7. #define LAT 30.57           //纬度


  8. sbit LCD_SCLK = P0^0;
  9. sbit LCD_STD = P0^1;
  10. sbit LCD_CS = P0^2;


  11. sbit DS1302_CE = P3^1;
  12. sbit DS1302_CK = P3^4;
  13. sbit DS1302_IO = P3^5;

  14. extern void _nop_(void);


  15. uchar        time[8] ;
  16. uchar        set_buf[12] = {0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30};
  17. uchar   angle[3];
  18. uchar        time_500ms;
  19. uchar        set_num = 0;
  20. uchar        key_num;
  21. uchar        count1,count2;
  22. bit         flag_js;

  23. /* 发送一个字节到DS1302通信总线上 */
  24. void DS1302ByteWrite(uchar dat)
  25. {
  26.     uchar mask;
  27.    
  28.     for (mask=0x01; mask!=0; mask<<=1)  //低位在前,逐位移出
  29.     {
  30.         if ((mask&dat) != 0) //首先输出该位数据
  31.             DS1302_IO = 1;
  32.         else
  33.             DS1302_IO = 0;
  34.         DS1302_CK = 1;       //然后拉高时钟
  35.         DS1302_CK = 0;       //再拉低时钟,完成一个位的操作
  36.     }
  37.     DS1302_IO = 1;           //最后确保释放IO引脚
  38. }
  39. /* 由DS1302通信总线上读取一个字节 */
  40. unsigned char DS1302ByteRead()
  41. {
  42.     uchar mask;
  43.     uchar dat = 0;
  44.    
  45.     for (mask=0x01; mask!=0; mask<<=1)  //低位在前,逐位读取
  46.     {
  47.         if (DS1302_IO != 0)  //首先读取此时的IO引脚,并设置dat中的对应位
  48.         {
  49.             dat |= mask;
  50.         }
  51.         DS1302_CK = 1;       //然后拉高时钟
  52.         DS1302_CK = 0;       //再拉低时钟,完成一个位的操作
  53.     }
  54.     return dat;              //最后返回读到的字节数据
  55. }
  56. /* 用单次写操作向某一寄存器写入一个字节,reg-寄存器地址,dat-待写入字节 */
  57. void DS1302SingleWrite(uchar reg, uchar dat)
  58. {
  59.     DS1302_CE = 1;                   //使能片选信号
  60.     DS1302ByteWrite((reg<<1)|0x80);  //发送写寄存器指令
  61.     DS1302ByteWrite(dat);            //写入字节数据
  62.     DS1302_CE = 0;                   //除能片选信号
  63. }
  64. /* 用单次读操作从某一寄存器读取一个字节,reg-寄存器地址,返回值-读到的字节 */
  65. unsigned char DS1302SingleRead(uchar reg)
  66. {
  67.     uchar dat;
  68.    
  69.     DS1302_CE = 1;                   //使能片选信号
  70.     DS1302ByteWrite((reg<<1)|0x81);  //发送读寄存器指令
  71.     dat = DS1302ByteRead();          //读取字节数据
  72.     DS1302_CE = 0;                   //除能片选信号
  73.    
  74.     return dat;
  75. }
  76. /* 用突发模式连续写入8个寄存器数据,dat-待写入数据指针 */
  77. void DS1302BurstWrite(unsigned char *dat)
  78. {
  79.     uchar i;
  80.    
  81.     DS1302_CE = 1;
  82.     DS1302ByteWrite(0xBE);  //发送突发写寄存器指令
  83.     for (i=0; i<8; i++)     //连续写入8字节数据
  84.     {
  85.         DS1302ByteWrite(dat[i]);
  86.     }
  87.     DS1302_CE = 0;
  88. }
  89. /* 用突发模式连续读取8个寄存器的数据,dat-读取数据的接收指针 */
  90. void DS1302BurstRead(uchar *dat)
  91. {
  92.     uchar i;
  93.    
  94.     DS1302_CE = 1;
  95.     DS1302ByteWrite(0xBF);  //发送突发读寄存器指令
  96.     for (i=0; i<8; i++)     //连续读取8个字节
  97.     {
  98.         dat[i] = DS1302ByteRead();
  99.     }
  100.     DS1302_CE = 0;
  101. }
  102. /* DS1302初始化,如发生掉电则重新设置初始时间 */
  103. void InitDS1302()
  104. {
  105.     uchar dat;
  106.     uchar code InitTime[] = {  //2020年4月1日 星期二 12:30:00
  107.         0x00,0x30,0x12, 0x01, 0x04, 0x02, 0x20
  108.     };
  109.    
  110.     DS1302_CE = 0;  //初始化DS1302通信引脚
  111.     DS1302_CK = 0;
  112.     dat = DS1302SingleRead(0);  //读取秒寄存器
  113.     if ((dat & 0x80) != 0)      //由秒寄存器最高位CH的值判断DS1302是否已停止
  114.     {
  115.         DS1302SingleWrite(7, 0x00);  //撤销写保护以允许写入数据
  116.         DS1302BurstWrite(InitTime);  //设置DS1302为默认的初始时间
  117.     }
  118. }

  119. //***********************************************************
  120. //函数:void key(void)
  121. //功能:键盘扫描、识别以及处理
  122. //***********************************************************
  123. void key(void)
  124. {
  125.         uchar        tmp,temp;
  126.     tmp=P1|0x07;
  127.         temp = tmp;
  128.         temp &= 0x07;
  129.         if(temp != key_num)
  130.         {
  131.                 key_num = temp;
  132.                 switch(key_num)
  133.                 {
  134.                         case 0x06: if(flag_js == 0)//设定/退出
  135.                         {
  136.                           flag_js = 1;
  137.                           count1  = 1;
  138.                                                    
  139.                         }
  140.                        else if(flag_js == 1)
  141.                         {
  142.                           time[6] = (set_buf[11]<<4)+(set_buf[10]&0x0f);//年
  143.                           
  144.                           time[4] = (set_buf[9]<<4)+(set_buf[8]&0x0f);//月
  145.                           time[3] = (set_buf[7]<<4)+(set_buf[6]&0x0f);//日
  146.                           time[2] = (set_buf[5]<<4)+(set_buf[4]&0x0f);//时
  147.                           time[1] = (set_buf[3]<<4)+(set_buf[2]&0x0f);//分
  148.                           time[0] = (set_buf[1]<<4)+(set_buf[0]&0x0f); //秒
  149.                           DS1302BurstWrite(time);
  150.                           flag_js = 0;
  151.                           count2  = 1;

  152.                          }
  153.                         break;
  154.                         case 0x05: if(flag_js == 1)//移位
  155.                                                 {
  156.                                                         set_num ++;
  157.                                                         if(set_num > 11)
  158.                                                         set_num = 0;
  159.                                                 }
  160.                                                 break;
  161.                         case 0x03: if(flag_js == 1)//数字加一
  162.                                                 {
  163.   switch(set_num)
  164.   {
  165.    case 0:  if(set_buf[0] > 0x38) set_buf[0] = 0x30; //秒的个位
  166.    else set_buf[0]++; break;
  167.    case 1:  if(set_buf[1] > 0x34) set_buf[1] = 0x30; //秒的十位
  168.    else set_buf[1]++; break;
  169.    case 2:  if(set_buf[2] > 0x38) set_buf[2] = 0x30;
  170.    else set_buf[2]++; break;
  171.    case 3:  if(set_buf[3] > 0x34) set_buf[3] = 0x30; //分
  172.    else set_buf[3]++; break;
  173.    case 4:  if(set_buf[4] > 0x38) set_buf[4] = 0x30;
  174.    else set_buf[4]++; break;
  175.    case 5:  if(set_buf[5] > 0x31) set_buf[5] = 0x30; //时
  176.    else set_buf[5]++; break;
  177.    case 6:  if(set_buf[6] > 0x38) set_buf[5] = 0x30;
  178.    else set_buf[6]++; break;
  179.    case 7:  if(set_buf[7] > 0x32) set_buf[5] = 0x30; //日
  180.   else set_buf[7]++; break;
  181.   case 8:  if(set_buf[8] > 0x38) set_buf[5] = 0x30;
  182.   else set_buf[8]++; break;
  183.   case 9:  if(set_buf[9] > 0x31) set_buf[5] = 0x30; //月
  184.   else set_buf[9]++; break;
  185.   case 10:  if(set_buf[10] > 0x38) set_buf[5] = 0x30;
  186.   else set_buf[10]++; break;
  187.   case 11:  if(set_buf[11] > 0x38) set_buf[5] = 0x30; //年
  188.   else set_buf[11]++; break;
  189.   default: break;
  190.                                                         }
  191.                                                 }
  192.                                                 break;

  193.                         default: break;
  194.                 }
  195.         }
  196. }
复制代码

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:401564 发表于 2020-4-6 17:25 | 只看该作者
用4个光敏电阻通过实时采光跟踪它不好吗?
冬天下午3点和夏天的下午3点,这太阳的方向是不一样的呀
回复

使用道具 举报

板凳
ID:710256 发表于 2020-4-6 17:51 | 只看该作者
这是算太阳角度,和主程序,望大佬指正

  1. /*计算太阳角度*/
  2. void anglecalculate()
  3. {  
  4.    int     leap;
  5.    uint    year,mon,day;
  6.    uint    hour,min,sec;
  7.    uint    DayAdd;
  8.    uchar   DecAngle,HourAngle,DecAngle1;
  9.    uchar   EleAngle,AziAngle,AziAngle1;
  10.    year=(time[6]>>4)*10+(time[6]&0x0f)+2000;
  11.    mon=(time[4]>>4)*10+(time[4]&0x0f);
  12.    day=(time[3]>>4)*10+(time[3]&0x0f);
  13.    hour=(time[2]>>4)*10+(time[2]&0x0f);
  14.    min=(time[1]>>4)*10+(time[1]&0x0f);
  15.    sec=(time[0]>>4)*10+(time[0]&0x0f);
  16.    leap=(year%4==0&&year%100!=0)||(year%400==0);闰年计算
  17.    switch(mon)
  18.           {
  19.             case 1:
  20.                   DayAdd=(day);break;
  21.             case 2:
  22.                   DayAdd=31+day;break;
  23.             case 3:
  24.                           DayAdd=31+28+day;break;
  25.             case 4:
  26.                           DayAdd=31+28+31+day;break;
  27.             case 5:
  28.                           DayAdd=31+28+31+30+day;break;
  29.             case 6:
  30.                           DayAdd=31+28+31+30+31+day;break;
  31.             case 7:
  32.                           DayAdd=31+28+31+30+31+30+day;break;
  33.             case 8:
  34.                       DayAdd=31+28+31+30+31+30+31+day;break;
  35.             case 9:
  36.                           DayAdd=31+28+31+30+31+30+31+31+day;break;
  37.             case 10:
  38.                           DayAdd=31+28+31+30+31+30+31+31+30+day;break;
  39.             case 11:
  40.                           DayAdd=31+28+31+30+31+30+31+31+30+31+day;break;
  41.             case 12:
  42.                           DayAdd=31+28+31+30+31+30+31+31+30+31+30+day;break;
  43.                 default:
  44.                       break;         /*cout<<"月份输入错误!*/
  45.           }
  46.   if(leap&&(mon>=3))
  47.   DayAdd=DayAdd+1; //当前天数  
  48.   DecAngle=(23.45*sin(2*PI*(284+DayAdd)/365))*PI/180;//计算赤纬角
  49.   DecAngle1=(23.45*sin(2*PI*(284+DayAdd+1)/365))*PI/180;//计算第二天赤纬角
  50.   HourAngle=(12-(hour)-(min)/60.0-(sec)/3600.0)*PI/12;//计算时角
  51.   EleAngle=asin(sin(LAT)*sin(DecAngle)+cos(LAT )*cos(DecAngle)*cos(HourAngle));//计算高度角
  52.   AziAngle=acos((sin(EleAngle)*sin(LAT )-sin(DecAngle))/(cos(EleAngle)*cos(LAT )));//计算方位角
  53.   AziAngle1=acos((0-sin(DecAngle1))/cos(LAT ));//计算第二天的方位角
  54.   angle[0]=EleAngle;
  55.   angle[1]=AziAngle;
  56.   angle[2]=AziAngle1;
  57.   
  58.      
  59. }/*视日轨迹追踪*/
  60. void trackgo()
  61. {
  62.     uchar h,f;
  63.     uchar y,z;
  64.     uchar p,q;
  65.     uchar c=0,d=0;

  66.    
  67.     h=angle[0];//得到高度角
  68.     f=angle[1];//得到方位角
  69.     y=(f-c)/5;//计算方位电机需旋转圈数
  70.     z=(h-d)/1;//计算高度电机需旋转圈数
  71.     c=f;
  72.     d=h;
  73.     if(y!=0)
  74.     {              
  75.       for(p=0;p<y;p++)
  76.        {
  77.         GoA1();
  78.        }
  79.      }
  80.     else
  81.      {  
  82.        if(z!=0)
  83.         {            
  84.          for(q=0;q<z;q++)
  85.           {
  86.             GoB1();
  87.            }
  88.          }
  89.       }            
  90.     P2=0x00;
  91. }
  92. //函数:void main()功能:主函数,初始化
  93. void main()
  94. {
  95.     uchar psec=0xaa;
  96.     uchar time_30s=0;
  97.     uint getdata;
  98.     float temp;
  99.    
  100.     P2=0x00;
  101.         time_500ms = 0;
  102.         flag_js = 0;
  103.         count1 = 1;
  104.         count2 = 1;

  105.     InitDS1302();
  106.     timer_init();
  107.     Out_Init();
  108.    LCD_init();
  109.        
  110.     delay_ms(50);

  111.     E_W_ANGLE=read2543(0x00);
  112.     S_N_ANGLE=read2543(0x10);
  113.     LIGHT_DETECTION=read2543(0x20);
  114.    
  115.         while(1)
  116.         {
  117.       
  118.        if(time_500ms == 50)
  119.        {
  120.             time_500ms=0;
  121.             DS1302BurstRead(time);//获得时间
  122.             key();
  123.             anglecalculate();
  124.             if(psec!=time[0])
  125.              {                       
  126.                            disp(flag_js); //用液晶显示时间
  127.                psec=time[0];
  128.               }
  129.             time_30s++;
  130.         
  131.             if(time_30s==6)//3s判定一次方位
  132.              {
  133.                  time_30s=0;
  134.                  getdata=read2543(0x20);
  135.                  getdata=read2543(0x20);
  136.                  getdata=read2543(0x20);
  137.                  temp=(float)getdata/4095*500;
  138.                  LIGHT_DETECTION=temp;//当前光照强度
  139.                  temp=0;

  140.                  if(LIGHT_DETECTION<300&&LIGHT_DETECTION>100)//光强不足启用视日轨迹追踪
  141.                   {
  142.                      trackgo();           
  143.                    }            
  144.             }
  145.       
  146.             startgo();
  147.        }
  148.         }
  149. }
复制代码
回复

使用道具 举报

地板
ID:710256 发表于 2020-4-6 20:37 | 只看该作者
Y_G_G 发表于 2020-4-6 17:25
用4个光敏电阻通过实时采光跟踪它不好吗?
冬天下午3点和夏天的下午3点,这太阳的方向是不一样的呀

用采光跟踪只是其中一部分还要与轨迹跟踪相配合,光强不够,天气不好就启用轨迹跟踪
回复

使用道具 举报

5#
ID:401564 发表于 2020-4-7 09:36 | 只看该作者
astlaqwq 发表于 2020-4-6 20:37
用采光跟踪只是其中一部分还要与轨迹跟踪相配合,光强不够,天气不好就启用轨迹跟踪

你这估计是太阳能之类的,那天气不好的话,太阳能还有什么用呢?没有太阳,转哪不都一样的吗?有了太阳,就调整一下不就得了
而且,这经度时间什么的,你算过时区没有呀?我们用的是北京时间,你家在北京吗?大年三十的时候,新疆那边可是晚上八九点才天黑的
冬天和夏天的太阳轨迹也是不一样的
采光跟踪已经可以解决很多问题
回复

使用道具 举报

6#
ID:710256 发表于 2020-4-7 12:49 | 只看该作者
Y_G_G 发表于 2020-4-7 09:36
你这估计是太阳能之类的,那天气不好的话,太阳能还有什么用呢?没有太阳,转哪不都一样的吗?有了太阳,就调整 ...

我主要是实现在白天实现全天候的太阳追踪所以需要两种方式一起用,至于经度的校正没有进行,不需要太精确,能力有限,看了一堆资料被一大堆公式绕了进去
回复

使用道具 举报

7#
ID:678200 发表于 2020-4-9 17:57 | 只看该作者
求仿真跟程序,学习一下
回复

使用道具 举报

8#
ID:671688 发表于 2023-3-9 14:01 | 只看该作者
求仿真跟程序,学习一下
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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