五、IIC、RTC、BUZZ

1、EEPROM

* 实验目的:1.掌握EEPROM AT24C02的操作方法
*           2.掌握I2C总线协议和通讯原理
* 程序说明:1.从EEPROM 0xff地址读出数据dat,++dat后重新写回0xff地址
*           2.通过LCD显示0xff地址存储的数据,每次复位后,数值加1

本次实验通过GPIO引脚模仿IIC通信,同时利用外置的EEPROM存储达到断电保存的目的;

IC(Inter-Integrated Circuit)总线是一种由 PHILIPS 公司开发的两线式串行总线,用于连接
微控制器及其外围设备。它是由数据线 SDA 和时钟 SCL 构成的串行总线,可发送和接收数据。
在 CPU 与被控 IC 之间、 IC 与 IC 之间进行双向传送, 高速 IIC 总线一般可达 400kbps 以上。
I2C 总线在传送数据过程中共有三种类型信号, 它们分别是:开始信号、结束信号和应答
信号。
开始信号: SCL 为高电平时, SDA 由高电平向低电平跳变,开始传送数据。
结束信号: SCL 为高电平时, SDA 由低电平向高电平跳变,结束传送数据。
应答信号:接收数据的 IC 在接收到 8bit 数据后,向发送数据的 IC 发出特定的低电平脉冲,
表示已收到数据。 CPU 向受控单元发出一个信号后,等待受控单元发出一个应答信号, CPU 接
收到应答信号后,根据实际情况作出是否继续传递信号的判断。若未收到应答信号,由判断为
受控单元出现故障。
这些信号中,起始信号是必需的,结束信号和应答信号,都可以不要。 IIC 总线时序图如

 程序:

①、库函数

②、主函数

一般考场提供i2c的文件(注意与硬件自带的i2c的区别,后者库文件与前文添加方式一样)

#include "stm32f10x.h"
#include <stdio.h>
#include "lcd.h"
#include "i2c.h"

uint32_t TimingDelay = 0;
void Delay_Ms(uint32_t nTime);
u8 Read_Byte(u8 address);
u8 Write_Byte(char address,char info);

int main(void)
{

	u8 temp,string[20];
   SysTick_Config(SystemCoreClock/1000);

   	STM3210B_LCD_Init();
	LCD_Clear(White);
	LCD_SetTextColor(White);
	LCD_SetBackColor(Blue);
    
	LCD_ClearLine(Line0);
	LCD_ClearLine(Line1);
	LCD_ClearLine(Line2);
	LCD_ClearLine(Line3);
	LCD_ClearLine(Line4);


  LCD_DisplayStringLine(Line1,"      I2C DEMO      ");
  LCD_DisplayStringLine(Line3,"     AT24C02 R/W    ");

    LCD_SetTextColor(Blue);
	LCD_SetBackColor(White);

	i2c_init();	
	temp =Read_Byte(0xff);
	Delay_Ms(2);
	Write_Byte(0xff,++temp);
	Delay_Ms(2);
	sprintf((char *)string,"%s%d","ADDR:0XFF,VAL:",temp);

	LCD_DisplayStringLine(Line6,string);



  while (1)
  {
  }
}


u8 Read_Byte(u8 address)
{
char val;

I2CStart();
I2CSendByte(0xa0);
I2CWaitAck();

I2CSendByte(address);
I2CWaitAck();

I2CStart();
I2CSendByte(0xa1);
I2CWaitAck();
val=I2CReceiveByte();
I2CWaitAck();
I2CStop();

return val;



}

u8 Write_Byte(char address,char info)
{
I2CStart();
I2CSendByte(0xa0) ;
I2CWaitAck();

I2CSendByte(address);
I2CWaitAck();
I2CSendByte(info);
I2CWaitAck();

I2CStop();



}

void Delay_Ms(uint32_t nTime)
{
    TimingDelay = nTime;
    while(TimingDelay != 0);
}


 

我们是AT24C02为2K空间,所以地址为:1010000x, R/W为读写位,其中W为0,R为1。2Kb空间,一个储存空间为一个字节,8bit,所以地址需要:2048/8=256个,0-0xFF。

在蓝桥杯的驱动中,我们只需要两个函数即可,一个是读(at24c02_readbyte),一个是写(at24c02_writebyte)。

先来看写时序:

 

操作顺序为:START->write device address(0xA0)->wait ack->write word address->wait ack->write data->wait ack->stop.

 

蓝桥杯驱动系列之外部存储器【如需转载请联系博主】

同理操作顺序为:start->write device address(0xA0)->wait ack->write word address->wait ack->start->write device address(0xA0+1)->wait ack->read data->no ack->stop

其实时序程序难点就是理清操作的顺序,搞清楚后,程序自然就出来了。严格按照时序写,程序当然也不会出错。读操作注意的是:初开始有一个start外,中间包含了一个start,同时发送了读器件地址(0XA1)。

实际使用的掉电储存,就是在程序运行最开始,把数据从EEPROM读出来。在程序运行过程中,若修改了参数,就保存在EEPROM中。

这里就不总结IIC的写法了,如果自己写,或者参考人家的。有几个注意的地方,SDA线是双向IO,在自己开发时,如果更改了IO,就需要修改。当Read时,SDA为输入模式;当Write时,SDA为输出模式。另外SDA数据的保持时间,与时钟线SCL的频率也都是注意的地方。一般IIC速度不超过400k。

2、RTC

 

* 实验目的:掌握STM32外设RTC的配置和使用方法
* 程序说明:CT117E竞赛平台无外部低速晶振,因此例程中使用内部低速振荡器LSI作为
*           RTC时钟。

 

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

RTC 由两个主要部分组成, 第一部分(APB1 接口)用来和 APB1 总线相连。
此单元还包含一组 16 位寄存器,可通过 APB1 总线对其进行读写操作。 APB1 接口由 APB1 总
线时钟驱动,用来与 APB1 总线连接。
另一部分(RTC 核心)由一组可编程计数器组成,分成两个主要模块。第一个模块是 RTC 的
预分频模块,它可编程产生 1 秒的 RTC 时间基准 TR_CLK。 RTC 的预分频模块包含了一个 20
位的可编程分频器(RTC 预分频器)。如果在 RTC_CR 寄存器中设置了相应的允许位,则在每个
TR_CLK 周期中 RTC 产生一个中断(秒中断)。第二个模块是一个 32 位的可编程计数器,可被
初始化为当前的系统时间,一个 32 位的时钟计数器,按秒钟计算,可以记录 4294967296 秒,
约合 136 年左右,作为一般应用,这已经是足够了的。

 


①、库文件(较多)

②主函数

#include "stm32f10x.h"
#include <stdio.h>
#include "lcd.h"
#include "i2c.h"



#define HH 11 //时
#define MM 59  //分
#define SS 55  //秒

uint32_t TimingDelay = 0;
void Delay_Ms(uint32_t nTime);



uint32_t TimeDisplay = 0;
/* Private function prototypes -----------------------------------------------*/
void Delay_Ms(uint32_t nTime);
void RTC_Configuration(void);
void NVIC_Configuration(void);
void Time_Display(u32 TimeVar);

int main(void)
{


   SysTick_Config(SystemCoreClock/1000);

   	STM3210B_LCD_Init();
	LCD_Clear(White);
	LCD_SetTextColor(White);
	LCD_SetBackColor(Blue);
    
	LCD_ClearLine(Line0);
	LCD_ClearLine(Line1);
	LCD_ClearLine(Line2);
	LCD_ClearLine(Line3);
	LCD_ClearLine(Line4);


  LCD_DisplayStringLine(Line1,"      RTC DEMO      ");
  LCD_DisplayStringLine(Line3,"        TEST        ");

    LCD_SetTextColor(Blue);
	LCD_SetBackColor(White);

	RTC_Configuration();
	NVIC_Configuration();

  while (1)
  {
    /* If 1s has been elapsed */
    if (TimeDisplay == 1)
    {
      /* Display current time */
      Time_Display(RTC_GetCounter());
      TimeDisplay = 0;
    }
}
 }

void NVIC_Configuration(void)
{
  NVIC_InitTypeDef NVIC_InitStructure;

  /* Configure one bit for preemption priority */
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);

  /* Enable the RTC Interrupt */
  NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
}

/**
  * @brief  Configures the RTC.
  * @param  None
  * @retval None
  */
void RTC_Configuration(void)
{
  /* Enable PWR and BKP clocks */
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);

  /* Allow access to BKP Domain */
  PWR_BackupAccessCmd(ENABLE);

  /* Reset Backup Domain */
  BKP_DeInit();

  /* Enable LSE */
  RCC_LSICmd(ENABLE);
  /* Wait till LSE is ready */
  while (RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET)
  {}

  /* Select LSE as RTC Clock Source */
  RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);

  /* Enable RTC Clock */
  RCC_RTCCLKCmd(ENABLE);

  /* Wait for RTC registers synchronization */
  RTC_WaitForSynchro();

  /* Wait until last write operation on RTC registers has finished */
  RTC_WaitForLastTask();

  /* Enable the RTC Second */
  RTC_ITConfig(RTC_IT_SEC, ENABLE);

  /* Wait until last write operation on RTC registers has finished */
  RTC_WaitForLastTask();

  /* Set RTC prescaler: set RTC period to 1sec */
  RTC_SetPrescaler(39999); /* RTC period = RTCCLK/RTC_PR = (40 KHz)/(39999+1) */

  /* Wait until last write operation on RTC registers has finished */
  RTC_WaitForLastTask();
  
//  RTC_SetCounter(HH*3600+MM*60+SS);
//  RTC_WaitForLastTask();
}


 u8 text[20];
 void Time_Display(uint32_t TimeVar)
{
  uint32_t THH = 0, TMM = 0, TSS = 0;
  
  /* Reset RTC Counter when Time is 23:59:59 */
  if (RTC_GetCounter() == 0x0001517F)
  {
     RTC_SetCounter(0x0);
     /* Wait until last write operation on RTC registers has finished */
     RTC_WaitForLastTask();
  }
  
  /* Compute  hours */
  THH = TimeVar / 3600;
  /* Compute minutes */
  TMM = (TimeVar % 3600) / 60;
  /* Compute seconds */
  TSS = (TimeVar % 3600) % 60;

  sprintf(text,"Time: %0.2d:%0.2d:%0.2d", THH, TMM, TSS);

  LCD_DisplayStringLine(Line7,text);


}





void Delay_Ms(uint32_t nTime)
{
    TimingDelay = nTime;
    while(TimingDelay != 0);
}


 

③、中断服务函数

void RTC_IRQHandler(void)
{
  if (RTC_GetITStatus(RTC_IT_SEC) != RESET)
  {
    /* Clear the RTC Second interrupt */
    RTC_ClearITPendingBit(RTC_IT_SEC);

    /* Toggle LED1 */
 

    /* Enable time update */
    TimeDisplay = 1;

    /* Wait until last write operation on RTC registers has finished */
    RTC_WaitForLastTask();
    
  }
}

这里需要注意的是:①使能电源时钟和备份区域时钟。
前面已经介绍了,我们要访问 RTC 和备份区域就必须先使能电源时钟和备份区域时钟。
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);

②因为针对改款板子,RTC选用的是内部的低速时钟为40khz,故设置 RTC 时钟分频数,

RTC_SetPrescaler(39999); /* RTC period = RTCCLK/RTC_PR = (40 KHz)/(39999+1) */

 

3、BUZZ
  
        调试程序前,需将PB4-Buzzer跳线(红色)取下,待程序调试结束后,
        再接好跳线。
        PB4引脚上电默认为JTAG-RST引脚。 
        
     注意事项: 下载本程序后,将JTAG引脚重映射的普通IO功能,可能使得
                下载功能失效,恢复的方法是:
                
                1.按住板子上的RESET按键
                2.点击REALVIEW MDK软件上的DOWNLOAD按钮
                3.直到此时,松开板子上的复位按键,自动完成程序下载
                
                下载功能恢复后,以后再下载代码则不需要此过程。


①、库文件

②、代码

#include "stm32f10x.h"
#include <stdio.h>
#include "lcd.h"
#include "i2c.h"

uint32_t TimingDelay = 0;
void Delay_Ms(uint32_t nTime);

void  GPIO_Configuration(void);

int main(void)
{


   SysTick_Config(SystemCoreClock/1000);

   GPIO_Configuration();

   	STM3210B_LCD_Init();
	LCD_Clear(White);
	LCD_SetTextColor(White);
	LCD_SetBackColor(Blue);
    
	LCD_ClearLine(Line0);
	LCD_ClearLine(Line1);
	LCD_ClearLine(Line2);
	LCD_ClearLine(Line3);
	LCD_ClearLine(Line4);


  LCD_DisplayStringLine(Line1,"        BUZZ        ");
  LCD_DisplayStringLine(Line3,"        TEST        ");

    LCD_SetTextColor(Blue);
	LCD_SetBackColor(White);

	GPIO_PinRemapConfig(GPIO_Remap_SWJ_Disable, ENABLE);//重映射

	
  while (1)
  {
     GPIO_SetBits(GPIOB,GPIO_Pin_4);
	 Delay_Ms(1000);

	 GPIO_ResetBits(GPIOB,GPIO_Pin_4);
	 Delay_Ms(1000);
  }
}


void  GPIO_Configuration(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB |RCC_APB2Periph_AFIO, ENABLE);

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

    GPIO_Init(GPIOB, &GPIO_InitStructure);

}


void Delay_Ms(uint32_t nTime)
{
    TimingDelay = nTime;
    while(TimingDelay != 0);
}


这里值得注意的是,

由电路图知蜂鸣器与jtag共用一个引脚所以涉及重映射 (PB4/JNTRST),同时下载的时候需要注意按住reset键;

同时对于重映射,下面三句是等效的

    GPIO_PinRemapConfig(GPIO_Remap_SWJ_NoJTRST,ENABLE); //PB4 重映射
    GPIO_PinRemapConfig(GPIO_Remap_SWJ_Disable,ENABLE);    
    GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);

 

其余的配置一下引脚PB4即可使用,由npn三极管特性知低电平即可使蜂鸣器响。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

身在江湖的郭大侠

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值