打印

【连载】STM32f107&f407开发板(科星F107)学习笔记基础篇(更新中

[复制链接]
楼主: ren0zhe
手机看帖
扫描二维码
随时随地手机跟帖
61
不错

使用特权

评论回复
62
ren0zhe|  楼主 | 2013-10-24 10:28 | 只看该作者
本帖最后由 ren0zhe 于 2013-11-4 10:37 编辑

第十三节    实时时钟RTC实现时间戳的学习

实时时钟是一个独立的定时器。RTC模块拥有一组连续计数的计数器,在相应软件配置下,可提供时钟日历的功能。修改计数器的值可以重新设置系统当前的时间和日期。RTC模块和时钟配置系统(RCC_BDCR寄存器)处于后备区域,即在系统复位或从待机模式唤醒后,RTC的设置和时间维持不变。 系统复位后,对后备寄存器和RTC的访问被禁止,这是为了防止对后备区域(BKP)的意外写操作。


本节主要讲了 RTC的配置和使用time.c库文件中的函数,将寄存器中的值转化为日历形式的时间

pdf版学习笔记
13科星F107开发板学习笔记—RTC实现时间戳的学习.pdf (435.4 KB)

源码工程文件
13科星F107开发板学习笔记源码—RTC实现时间戳的学习.rar (3.7 MB)




学习笔记的部分内容如下:

执行以下操作将使能对后备寄存器和RTC的访问:
● 设置寄存器RCC_APB1ENR的PWREN和BKPEN位,使能电源和后备接口时钟
● 设置寄存器PWR_CR的DBP位,使能对后备寄存器和RTC的访问。
主要特性
● 可编程的预分频系数:分频系数最高为220
32位的可编程计数器,可用于较长时间段的测量。
2个分离的时钟:
用于APB1接口的PCLK1RTC时钟(RTC时钟的频率必须小于PCLK1时钟频率的四分之一以上)
● 可以选择以下三种RTC的时钟源:
HSE时钟除以128
LSE振荡器时钟;
LSI振荡器时钟
2个独立的复位类型:
APB1接口由系统复位;
RTC核心(预分频器、闹钟、计数器和分频器)只能由后备域复位
3个专门的可屏蔽中断:
闹钟中断,用来产生一个软件可编程的闹钟中断。
秒中断,用来产生一个可编程的周期性中断信号(最长可达1)
溢出中断,指示内部可编程计数器溢出并回转为0的状态。
功能描述
RTC由两个主要部分组成(参见下图)。第一部分(APB1接口)用来和APB1总线相连。此单元还包含一组16位寄存器,可通过APB1总线对其进行读写操作。APB1接口由APB1总线时钟驱动,用来与APB1总线接口。 另一部分(RTC核心)由一组可编程计数器组成,分成两个主要模块。第一个模块是RTC的预分频模块,它可编程产生最长为1秒的RTC时间基准TR_CLK。RTC的预分频模块包含了一个20位的可编程分频器(RTC预分频器)。如果在RTC_CR寄存器中设置了相应的允许位,则在每个TR_CLK周期中RTC产生一个中断(秒中断)。第二个模块是一个32位的可编程计数器,可被初始化为当前的系统时间。系统时间按TR_CLK周期累加并与存储在RTC_ALR寄存器中的可编程时间相比较,如果RTC_CR控制寄存器中设置了相应允许位,比较匹配时将产生一个闹钟中断。

下面我们看一下这一节我们用到的就是一个32.768K的外部晶振,如下图。它作为RTC的时钟源。
另外我们需要通过串口打印出数据,所以我们需要短接串口跳线:

短接图示的引脚如图:

下面我们进行代码的编写:
首先我们打开,第二节中新建的空工程,没有的朋友可以在下面的链接中找到:
下面我们打开这个工程,

第一步,由于我们这里要使用到库文件中RTC、串口配置等外设的函数,这里需要添加外设库文件,文件的路径为“\Libraries\STM32F10x_StdPeriph_Driver\src”。这里我们也要把封装好的RTC操作的文件RTC_Time.c和RTC_Time.h复制粘贴到工程的文件夹中,并且把RTC_Time.c添加到User组。配置完成如下图:


第二步,右击工程文件名,打开“Options”,找到“GerenalOptions”中的“Library Configuration”,在Library选项选择“Full”,如下图:

第三步,添加C语言标准输入输出的头文件#include <stdio.h>,其余的关于printf函数的代码就不多说了,不了解的请看第六节串口输出的内容。



下面我们看一下外设的配置函数:

void Init_Device(void)
{
   RCC_Configuration();
   NVIC_Configuration();
   GPIO_Configuration();
   USART_Configuration();
    RTC_Config();
}
这里讲一下函数RTC_Config();其实它并不是配置RTC的函数,它是一个自动检查是否需要RTC初始化的函数。我们在BKP的后备寄存器1中,存了一个特殊字符0xA5A5,第一次上电或后备电源掉电后,该寄存器数据丢失,表明RTC数据丢失,需要重新配置,这里这个函数就是检查这个“0xA5A5”的,如果在寄存器中检测不到这个标志,就重新配置RTC,如果检测到了就不用重新配置了,实现代码如下:

    if(BKP_ReadBackupRegister(BKP_DR1) != 0xA5A5)
    {
          //重新配置RTC
          RTC_Configuration();
          //配置完成后,向后备寄存器中写特殊字符0xA5A5
         BKP_WriteBackupRegister(BKP_DR1, 0xA5A5);
    }
    else
    {
……………..
}
下面我们来看一下配置RTC的函数,如下:
voidRTC_Configuration(void)
{
    //后备域解锁,也就是使能后备域,可以访问后备域寄存器
    PWR_BackupAccessCmd(ENABLE);
    //备份寄存器模块复位
    BKP_DeInit();
    //配置LSE。外部32.768K那个
    RCC_LSEConfig(RCC_LSE_ON);
    //等待稳定
    while (RCC_GetFlagStatus(RCC_FLAG_LSERDY)== RESET);
    //RTC时钟源配置成LSE(外部32.768K)
    RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
    //RTC开启
    RCC_RTCCLKCmd(ENABLE);
    //开启后需要等待APB1时钟与RTC时钟同步,才能读写寄存器
    RTC_WaitForSynchro();
    //读写寄存器前,要确定上一个操作已经结束
    RTC_WaitForLastTask();
    //设置RTC分频器,使RTC时钟为1Hz
//RTC period = RTCCLK/RTC_PR = (32.768KHz)/(32767+1)

    RTC_SetPrescaler(32767);
    //等待寄存器写入完成
    RTC_WaitForLastTask();
    //使能秒中断
    RTC_ITConfig(RTC_IT_SEC, ENABLE);   
    //等待写入完成
    RTC_WaitForLastTask();
}




QQ截图20131104102417.png (41.28 KB )

QQ截图20131104102417.png

使用特权

评论回复
63
jinlierwei| | 2013-10-25 16:30 | 只看该作者
都看不懂啊,没学过计算机的知识,但想学PLC,该怎么办呢?

使用特权

评论回复
64
ren0zhe|  楼主 | 2013-10-26 10:05 | 只看该作者
jinlierwei 发表于 2013-10-25 16:30
都看不懂啊,没学过计算机的知识,但想学PLC,该怎么办呢?

那买个PLC去玩吧,哥哥

使用特权

评论回复
65
ren0zhe|  楼主 | 2013-10-27 10:00 | 只看该作者
第十四节  DS18B20温度传感器读取温度的学习
         
本节主要讲了GPIO的操作和DS18B20温度传感器的使用


学习笔记的pdf版:
14科星F107开发板学习笔记—DS18B20温度传感器的学习.pdf (439.34 KB)

源码工程文件
14科星F107开发板学习笔记源码—DS18B20温度传感器的学习.rar (3.01 MB)






笔记的部分内容如下:

首先我们看一下科星F107开发板关于DS18B20的硬件原理图:
                              
         
如上图所示,MCU通过PD7引脚连接DS18B20的DQ(数字信号输入/输出端)进行指令和数据的交互,所以我们需要配置PD7这个GPIO口。
下面我们讲一下DS18B20的使用(更加详细的资料,请查阅DS18B20的芯片手册)
DS18B20测温系统具有测温系统简单、测温精度高、连接方便、占用口线少等优点。DS18B20默认为单总线12位(二进制)温度读数。内部有64位唯一的ID编码。工作电压从3.0~5.5V。测量温度范围从-55℃~125℃。最高±0.0625℃分辩率。
有两种实现读取温度的方式:
1DS18B20寄生电源供电方式电路
在寄生电源供电方式下,DS18B20从单线信号线上汲取能量:在信号线DQ处于高电平期间把能量储存在内部电容里,在信号线处于低电平期间消耗电容上的电能工作,直到高电平到来再给寄生电源(电容)充电。
   
    独特的寄生电源方式有三个好处:
   
    1)进行远距离测温时,无需本地电源
    2)可以在没有常规电源的条件下读取ROM
    3)电路更加简洁,仅用一根I/O口实现测温
这种方式对供电电压要求比较高 必须在5v 不然会造成很大的误差,DS18B20的VDD 引脚必须接地,只适合简单的单点采集。可靠性难以保证,不能用电池供电。一般不建议采用。
2DS18B20的外部电源供电方式
在外部电源供电方式下,DS18B20工作电源由VDD引脚接入,此时I/O线不需要强上拉,不存在电源电流不足的问题,可以保证转换精度,同时在总线上理论可以挂接任意多个DS18B20传感器,组成多点测温系统。注意:在外部供电的方式下,DS18B20的GND引脚不能悬空,否则不能转换温度,读取的温度总是85℃。
         外部电源供电方式是DS18B20最佳的工作方式,工作稳定可靠,抗干扰能力强,而且电路也比较简单,可以开发出稳定可靠的多点温度监控系统。
DS18B20使用中注意事项
DS18B20虽然具有测温系统简单、测温精度高、连接方便、占用口线少等优点,但在实际应用中也应注意以下几方面的问题:
较小的硬件开销需要相对复杂的软件进行补偿,由于DS18B20与微处理器间采用串行数据传送,因此,在对DS18B20进行读写编程时,必须严格的保证读写时序,否则将无法读取测温结果。在使用PL/M、C等高级语言进行系统程序设计时,对DS18B20操作部分最好采用汇编语言实现。
在DS18B20的有关资料中均未提及单总线上所挂DS18B20数量问题,容易使人误认为可以挂任意多个DS18B20,在实际应用中并非如此。当单总线上所挂DS18B20超过8个时,就需要解决微处理器的总线驱动问题,这一点在进行多点测温系统设计时要加以注意。
连接DS18B20的总线电缆是有长度限制的。试验中,当采用普通信号电缆传输长度超过50m时,读取的测温数据将发生错误。当将总线电缆改为双绞线带屏蔽电缆时,正常通讯距离可达150m,当采用每米绞合次数更多的双绞线带屏蔽电缆时,正常通讯距离进一步加长。这种情况主要是由总线分布电容使信号波形产生畸变造成的。因此,在用DS18B20进行长距离测温系统设计时要充分考虑总线分布电容和阻抗匹配问题。
在DS18B20测温程序设计中,向DS18B20发出温度转换命令后,程序总要等待DS18B20的返回信号,一旦某个DS18B20接触不好或断线,当程序读该DS18B20时,将没有返回信号,程序进入死循环。这一点在进行DS18B20硬件连接和软件设计时也要给予一定的重视。
测温电缆线建议采用屏蔽4芯双绞线,其中一对线接地线与信号线,另一组接VCC和地线,屏蔽层在源端单点接地
   
DS18B20内部寄存器映射如下图所示:
下面开始代码的编写,我们这里直接分析main()函数,功能就是获取温度值,然后每秒钟通过串口打印1次温度值。实现代码如下:
int main(void)
{
RCC_Configuration(); //配置时钟
GPIO_Configuration();//配置GPIO口,也配置了串口所用的GPIO
USART_Configuration();//配置串口通讯的参数
  if(SysTick_Config(720000)) //配置 点滴时钟的频率  
  {  
    while (1);
  }                                   
  while (1)
  {
    delay(100);  //延时1秒钟
   temp_18B20data=get18B20data();//获取温度值
    if(tempS==0)  //判断温度值的正负
     temper[0]='-';
    else
     temper[0]='+';
   
   temper[1]=temp_18B20data/100+0x30;     
   temper[2]=(temp_18B20data%100)/10+0x30;
   temper[3]='.';
   temper[4]=temp_18B20data%10+0x30;
   printf("\n\r 当前温度:");
   printf(temper);   //打印温度值
   printf("\n\r");
  }
}
这里我们主要讲温度获取函数get18B20data(),代码如下:
//从ds18b20得到温度值
//精度:0.1C
//返回值:温度值 (-550~1250
short get18B20data(void)
{
  u8 TL,TH;
  short tem;
  
  start18B20 ();  // ds18B20 startconvert   
  res18B20 (); //复位18B20
  check18B20 ();//检测18B20的存在   
  write18B20byte (0xcc);// 忽略 64 位ROM 地址,直接向 DS18B20 发温度变换命令
  write18B20byte (0xbe);// 读内部RAM 中9 字节的内容 的指令            
  TL=read18B20byte(); // LSB   连续读,先读去地位再读取高位数据
  TH=read18B20byte(); // MSB  
  if(TH>7)  //高5位为 符号位,只有高5位全为0时才为正号
  {
    TH=~TH;
    TL=~TL;
    tempS=0;//温度为负  
  }
  else
    tempS=1;//温度为正      
  tem=TH; //获得高八位
  tem<<=8;   
  tem+=TL;//获得低八位
  tem=(float)tem*0.625;//转换     
  return tem; //返回温度值  
}
第一步,开始温度转换,这里用到了DS18B20的指令0xcc和0x44。这些指令在DS18B20的芯片手册中都有,如下图(更多详细资料请查阅手册):
开始温度转换的函数如下:
//开始温度转换
void start18B20(void)// ds18B20 start convert
{                                                                  
  res18B20();   
  check18B20 ();      
  write18B20byte (0xcc);// 忽略 64 位 ROM 地址,直接向 DS18B20 发温度变换命令
  write18B20byte (0x44);// 启动DS18B20 进行温度转换,12 位转换时最长为750ms(9 位为93.75ms)。结果存入内部9 字节RAM 中。
}
第二步 进行温度数据的读取。先发送读取命令,然后进行温度数据的读取
  res18B20 (); //复位18B20
  check18B20 ();//检测18B20的存在   
  write18B20byte (0xcc);// 忽略 64 位 ROM 地址,直接向 DS18B20 发温度变换命令
  write18B20byte (0xbe);// 读内部RAM 中9 字节的内容 的指令            
  TL=read18B20byte(); // LSB   连续读,先读去地位再读取高位数据
  TH=read18B20byte(); // MSB  
第三步 温度数据的处理,提取符号位和数据位
数据的格式如下图,读取的两个字节中,高字节的二进制中的前面5 位是符号位,如果测得的温度大于0,这5 位为0,只要将测到的数值乘于0.0625 即可得到实际温度;如果温度小于0,这5 位为1,测到的数值需要取反加1 再乘于0.0625 即可得到实际温度。所以程序中当高字节大于7(0000 0111)时,符号位为负,否则为正。最后返回算出的温度值。
if(TH>7)  //高5位为 符号位,只有高5位全为0时才为正号
  {
    TH=~TH;
    TL=~TL;
    tempS=0;//温度为负
  }
  else
    tempS=1;//温度为正      
  tem=TH; //获得高八位
tem<<=8;   
  tem+=TL;//获得低八位
tem=(float)tem*0.625;//转换     
  return tem; //返回温度值  
这里的1s计时使用的是SysTick中断,中断处理函数为TimingDelay_Decrement();
下面把程序烧录到开发板,每秒钟会通过串口打印实时温度值,现象如下:

使用特权

评论回复
66
ren0zhe|  楼主 | 2013-10-29 16:14 | 只看该作者
现在在全力写 读写SD卡的学习笔记,FatFs的文件系统,准备写的更详细一些,让大家一看就懂,把文件系统这块搞定,光移植学不到什么,还得把里面的主要函数搞明白的。抄来抄去的真没意思

使用特权

评论回复
67
txcy| | 2013-10-29 16:17 | 只看该作者
很有参考价值的学习笔记

使用特权

评论回复
68
无冕之王| | 2013-10-29 16:29 | 只看该作者
鼓励多共享一些原创的学习笔记

使用特权

评论回复
69
pkat| | 2013-10-29 16:35 | 只看该作者
相当有用的学习笔记,尤其适合初学者

使用特权

评论回复
70
ren0zhe|  楼主 | 2013-10-30 14:29 | 只看该作者
txcy 发表于 2013-10-29 16:17
很有参考价值的学习笔记

多谢支持

使用特权

评论回复
71
dfsa| | 2013-10-30 16:42 | 只看该作者
看学习笔记还是很有用的

使用特权

评论回复
72
sinadz| | 2013-10-30 16:51 | 只看该作者
多看一些这样的学习笔记,还是相当有帮助的

使用特权

评论回复
73
秋天落叶| | 2013-10-30 17:00 | 只看该作者
很好的学习笔记

使用特权

评论回复
74
火箭球迷| | 2013-10-30 19:11 | 只看该作者
很有用的学习笔记

使用特权

评论回复
75
hsbjb| | 2013-10-30 19:22 | 只看该作者
很好的学习笔记

使用特权

评论回复
76
ren0zhe|  楼主 | 2013-10-31 07:50 | 只看该作者
无冕之王 发表于 2013-10-29 16:29
鼓励多共享一些原创的学习笔记

多谢支持,我们再接再厉!

使用特权

评论回复
77
ren0zhe|  楼主 | 2013-10-31 16:50 | 只看该作者
pkat 发表于 2013-10-29 16:35
相当有用的学习笔记,尤其适合初学者

多谢支持,我们也有网络篇的

使用特权

评论回复
78
xsgy123| | 2013-10-31 16:54 | 只看该作者
很喜欢这样的学习笔记,多谢分享

使用特权

评论回复
79
秋天落叶| | 2013-10-31 17:12 | 只看该作者
很给力的学习笔记

使用特权

评论回复
80
yybj| | 2013-10-31 18:26 | 只看该作者
还不错的一些学习笔记

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则