这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 电子DIY » (STM32_RAM调试)库函数操作篇(库函数操作:实验2 按键输入)蒋粤 AR

共78条 7/8 |‹ 3 4 5 6 7 8 跳转至
助工
2012-06-03 19:07:44     打赏
61楼

tm timer;//时钟结构体    
//实时时钟配置
//初始化RTC时钟,同时检测时钟是否工作正常
//BKP->DR1用于保存是否第一次配置的设置
//返回0:正常
//其他:错误代码
u8 RTC_Init(void)
{
 //检查是不是第一次配置时钟
 u8 temp=0;
 if(BKP->DR1!=0X5050)//第一次配置
 { 
    RCC->APB1ENR|=1<<28;     //使能电源时钟    
  RCC->APB1ENR|=1<<27;     //使能备份时钟    
  PWR->CR|=1<<8;           //取消备份区写保护
  RCC->BDCR|=1<<16;        //备份区域软复位   
  RCC->BDCR&=~(1<<16);     //备份区域软复位结束    
     RCC->BDCR|=1<<0;         //开启外部低速振荡器
     while((!(RCC->BDCR&0X02))&&temp<250)//等待外部时钟就绪 
  {
   temp++;
   delay_ms(10);
  };
  if(temp>=250)return 1;//初始化时钟失败,晶振有问题    

  RCC->BDCR|=1<<8; //LSI作为RTC时钟     
  RCC->BDCR|=1<<15;//RTC时钟使能  
    while(!(RTC->CRL&(1<<5)));//等待RTC寄存器操作完成 
     while(!(RTC->CRL&(1<<3)));//等待RTC寄存器同步 
     RTC->CRH|=0X01;      //允许秒中断
     while(!(RTC->CRL&(1<<5)));//等待RTC寄存器操作完成 
  RTC->CRL|=1<<4;              //允许配置   
  RTC->PRLH=0X0000;
  RTC->PRLL=32767;             //时钟周期设置(有待观察,看是否跑慢了?)理论值:32767          
  Auto_Time_Set();
  //RTC_Set(2009,12,2,10,0,55);  //设置时间  
  RTC->CRL&=~(1<<4);           //配置更新
  while(!(RTC->CRL&(1<<5)));   //等待RTC寄存器操作完成             
  BKP->DR1=0X5050;
  //BKP_Write(1,0X5050);;//在寄存器1标记已经开启了
  //printf("FIRST TIME\n");
 }else//系统继续计时
 {
     while(!(RTC->CRL&(1<<3)));//等待RTC寄存器同步 
     RTC->CRH|=0X01;      //允许秒中断
     while(!(RTC->CRL&(1<<5)));//等待RTC寄存器操作完成
  //printf("OK\n");
 }           
 MY_NVIC_Init(0,0,RTC_IRQChannel,2);//RTC,G2,P2,S2.优先级最低    
 RTC_Get();//更新时间
 return 0; //ok
}
//RTC中断服务函数  
//const u8* Week[2][7]=
//{
//{"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"},
//{"日","一","二","三","四","五","六"}
//};        
//RTC时钟中断
//每秒触发一次  
void RTC_IRQHandler(void)
{          
 if(RTC->CRL&0x0001)//秒钟中断
 {       
  RTC_Get();//更新时间  
  //printf("CRL:%d\n",RTC->CRL); 
  }
 if(RTC->CRL&0x0002)//闹钟中断
 {
  //printf("Alarm!\n"); 
  RTC->CRL&=~(0x0002);//清闹钟中断
   //闹钟处理
 }               
    RTC->CRL&=0X0FFA;         //清除溢出,秒钟中断标志
 while(!(RTC->CRL&(1<<5)));//等待RTC寄存器操作完成                  
}
//判断是否是闰年函数
//月份   1  2  3  4  5  6  7  8  9  10 11 12
//闰年   31 29 31 30 31 30 31 31 30 31 30 31
//非闰年 31 28 31 30 31 30 31 31 30 31 30 31
//输入:年份
//输出:该年份是不是闰年.1,是.0,不是
u8 Is_Leap_Year(u16 year)
{    
 if(year%4==0) //必须能被4整除
 {
  if(year%100==0)
  {
   if(year%400==0)return 1;//如果以00结尾,还要能被400整除    
   else return 0;  
  }else return 1;  
 }else return 0; 
}       
//设置时钟
//把输入的时钟转换为秒钟
//以1970年1月1日为基准
//1970~2099年为合法年份
//返回值:0,成功;其他:错误代码.
//月份数据表           
u8 const table_week[12]={0,3,3,6,1,4,6,2,5,0,3,5}; //月修正数据表  
//平年的月份日期表
const u8 mon_table[12]={31,28,31,30,31,30,31,31,30,31,30,31};
u8 RTC_Set(u16 syear,u8 smon,u8 sday,u8 hour,u8 min,u8 sec)
{
 u16 t;
 u32 seccount=0;
 if(syear<1970||syear>2099)return 1;   
 for(t=1970;t<syear;t++) //把所有年份的秒钟相加
 {
  if(Is_Leap_Year(t))seccount+=31622400;//闰年的秒钟数
  else seccount+=31536000;     //平年的秒钟数
 }
 smon-=1;
 for(t=0;t<smon;t++)    //把前面月份的秒钟数相加
 {
  seccount+=(u32)mon_table[t]*86400;//月份秒钟数相加
  if(Is_Leap_Year(syear)&&t==1)seccount+=86400;//闰年2月份增加一天的秒钟数   
 }
 seccount+=(u32)(sday-1)*86400;//把前面日期的秒钟数相加
 seccount+=(u32)hour*3600;//小时秒钟数
    seccount+=(u32)min*60;  //分钟秒钟数
 seccount+=sec;//最后的秒钟加上去
                
 //设置时钟
    RCC->APB1ENR|=1<<28;//使能电源时钟
    RCC->APB1ENR|=1<<27;//使能备份时钟
 PWR->CR|=1<<8;    //取消备份区写保护
 //上面三步是必须的!
 RTC->CRL|=1<<4;   //允许配置
 RTC->CNTL=seccount&0xffff;
 RTC->CNTH=seccount>>16;
 RTC->CRL&=~(1<<4);//配置更新
 while(!(RTC->CRL&(1<<5)));//等待RTC寄存器操作完成   
 return 0;    
}
//得到当前的时间
//返回值:0,成功;其他:错误代码.
u8 RTC_Get(void)
{
 static u16 daycnt=0;
 u32 timecount=0;
 u32 temp=0;
 u16 temp1=0;  
   
 timecount=RTC->CNTH;//得到计数器中的值(秒钟数)
 timecount<<=16;
 timecount+=RTC->CNTL;   

 temp=timecount/86400;   //得到天数(秒钟数对应的)
 if(daycnt!=temp)//超过一天了
 {  
  daycnt=temp;
  temp1=1970; //从1970年开始
  while(temp>=365)
  {    
   if(Is_Leap_Year(temp1))//是闰年
   {
    if(temp>=366)temp-=366;//闰年的秒钟数
    else break; 
   }
   else temp-=365;   //平年
   temp1++; 
  }  
  timer.w_year=temp1;//得到年份
  temp1=0;
  while(temp>=28)//超过了一个月
  {
   if(Is_Leap_Year(timer.w_year)&&temp1==1)//当年是不是闰年/2月份
   {
    if(temp>=29)temp-=29;//闰年的秒钟数
    else break;
   }
   else
   {
    if(temp>=mon_table[temp1])temp-=mon_table[temp1];//平年
    else break;
   }
   temp1++; 
  }
  timer.w_month=temp1+1;//得到月份
  timer.w_date=temp+1;  //得到日期
 }
 temp=timecount%86400;     //得到秒钟数      
 timer.hour=temp/3600;     //小时
 timer.min=(temp%3600)/60; //分钟 
 timer.sec=(temp%3600)%60; //秒钟
 timer.week=RTC_Get_Week(timer.w_year,timer.w_month,timer.w_date);//获取星期  
 return 0;

//获得现在是星期几
//功能描述:输入公历日期得到星期(只允许1901-2099年)
//输入参数:公历年月日
//返回值:星期号                      
u8 RTC_Get_Week(u16 year,u8 month,u8 day)

 u16 temp2;
 u8 yearH,yearL;
 
 yearH=year/100; yearL=year%100;
 // 如果为21世纪,年份数加100 
 if (yearH>19)yearL+=100;
 // 所过闰年数只算1900年之后的 
 temp2=yearL+yearL/4;
 temp2=temp2%7;
 temp2=temp2+day+table_week[month-1];
 if (yearL%4==0&&month<3)temp2--;
 return(temp2%7);
}
//比较两个字符串指定长度的内容是否相等
//参数:s1,s2要比较的两个字符串;len,比较长度
//返回值:1,相等;0,不相等
u8 str_cmpx(u8*s1,u8*s2,u8 len)
{
 u8 i;
 for(i=0;i<len;i++)if((*s1++)!=*s2++)return 0;
 return 1;   
}
extern const u8 *COMPILED_DATE;//获得编译日期
extern const u8 *COMPILED_TIME;//获得编译时间
const u8 Month_Tab[12][3]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
//自动设置时间为编译器时间  
void Auto_Time_Set(void)
{
 u8 temp[3];
 u8 i;
 u8 mon,date;
 u16 year;
 u8 sec,min,hour;
 for(i=0;i<3;i++)temp[i]=COMPILED_DATE[i];  
 for(i=0;i<12;i++)if(str_cmpx((u8*)Month_Tab[i],temp,3))break; 
 mon=i+1;//得到月份
 if(COMPILED_DATE[4]==' ')date=COMPILED_DATE[5]-'0';
 else date=10*(COMPILED_DATE[4]-'0')+COMPILED_DATE[5]-'0'; 
 year=1000*(COMPILED_DATE[7]-'0')+100*(COMPILED_DATE[8]-'0')+10*(COMPILED_DATE[9]-'0')+COMPILED_DATE[10]-'0';   
 hour=10*(COMPILED_TIME[0]-'0')+COMPILED_TIME[1]-'0'; 
 min=10*(COMPILED_TIME[3]-'0')+COMPILED_TIME[4]-'0'; 
 sec=10*(COMPILED_TIME[6]-'0')+COMPILED_TIME[7]-'0'; 
 RTC_Set(year,mon,date,hour,min,sec) ;
 //printf("%d-%d-%d  %d:%d:%d\n",year,mon,date,hour,min,sec);

详情请登录网友——正点原子官方论坛
http://www.openedv.com/forums/list.htm或下载《STM32不完全手册V2.0》
源代码:

实验10 RTC实时时钟实验.rar



助工
2012-06-03 19:10:31     打赏
62楼
//系统进入待机模式
void Sys_Enter_Standby(void)
{   
 //关闭所有外设(根据实际情况写)
    RCC->APB2RSTR|=0X01FC;//复位所有IO口
 Sys_Standby();//进入待机模式
}
//检测WKUP脚的信号
//返回值1:连续按下3s以上
//      0:错误的触发 
u8 Check_WKUP(void)
{
 u8 t=0;
 u8 tx=0;//记录松开的次数
 LED0=0; //亮灯DS0
 while(1)
 {
  if(WKUP_KD)//已经按下了
  {
   t++;
   tx=0;
  }else
  {
   tx++; //超过300ms内没有WKUP信号
   if(tx>3)
   {
    LED0=1;
    return 0;//错误的按键,按下次数不够
   }
  }
  delay_ms(30);
  if(t>=100)//按下超过3秒钟
  {
   LED0=0;   //点亮DS0
   return 1; //按下3s以上了
  }
 }

//中断,检测到PA0脚的一个上升沿.  
//中断线0线上的中断检测
void EXTI0_IRQHandler(void)
{                           
 EXTI->PR=1<<0;  //清除LINE10上的中断标志位   
 if(Check_WKUP())//关机?
 {   
  Sys_Enter_Standby(); 
 }
}
//PA0 WKUP唤醒初始化
void WKUP_Init(void)
{      
 RCC->APB2ENR|=1<<2;     //先使能外设IO PORTA时钟   
 RCC->APB2ENR|=1<<0;     //开启辅助时钟   
  
 GPIOA->CRL&=0XFFFFFFF0;//PA0设置成输入  
 GPIOA->CRL|=0X00000008; 
 Ex_NVIC_Config(GPIO_A,0,RTIR);//PA0上升沿触发   
                      
 //(检查是否是正常开)机      
    if(Check_WKUP()==0)Sys_Standby();    //不是开机,进入待机模式 
 MY_NVIC_Init(2,2,EXTI0_IRQChannel,2);//抢占2,子优先级2,组2
}

详情请登录网友——正点原子官方论坛
http://www.openedv.com/forums/list.htm或下载《STM32不完全手册V2.0》
源代码:
实验11 待机唤醒实验.rar

助工
2012-06-03 19:14:37     打赏
63楼

//初始化ADC
//这里我们仅以规则通道为例
//我们默认将开启通道0~3                   
void  Adc_Init(void)
{   
 //先初始化IO口
  RCC->APB2ENR|=1<<2;    //使能PORTA口时钟
 GPIOA->CRL&=0XFFFF0000;//PA0 1 2 3 anolog输入
 //通道10/11设置   
 RCC->APB2ENR|=1<<9;    //ADC1时钟使能  
 RCC->APB2RSTR|=1<<9;   //ADC1复位
 RCC->APB2RSTR&=~(1<<9);//复位结束    
 RCC->CFGR&=~(3<<14);   //分频因子清零 
 //SYSCLK/DIV2=12M ADC时钟设置为12M,ADC最大时钟不能超过14M!
 //否则将导致ADC准确度下降!
 RCC->CFGR|=2<<14;       

 ADC1->CR1&=0XF0FFFF;   //工作模式清零
 ADC1->CR1|=0<<16;      //独立工作模式 
 ADC1->CR1&=~(1<<8);    //非扫描模式  
 ADC1->CR2&=~(1<<1);    //单次转换模式
 ADC1->CR2&=~(7<<17);   
 ADC1->CR2|=7<<17;    //软件控制转换 
 ADC1->CR2|=1<<20;      //使用用外部触发(SWSTART)!!! 必须使用一个事件来触发
 ADC1->CR2&=~(1<<11);   //右对齐 
 ADC1->SQR1&=~(0XF<<20);
 ADC1->SQR1&=0<<20;     //1个转换在规则序列中 也就是只转换规则序列1      
 //设置通道0~3的采样时间
 ADC1->SMPR2&=0XFFFFF000;//通道0,1,2,3采样时间清空  
 ADC1->SMPR2|=7<<9;      //通道3  239.5周期,提高采样时间可以提高精确度 
 ADC1->SMPR2|=7<<6;      //通道2  239.5周期,提高采样时间可以提高精确度 
 ADC1->SMPR2|=7<<3;      //通道1  239.5周期,提高采样时间可以提高精确度 
 ADC1->SMPR2|=7<<0;      //通道0  239.5周期,提高采样时间可以提高精确度 

 ADC1->CR2|=1<<0;     //开启AD转换器 
 ADC1->CR2|=1<<3;        //使能复位校准 
 while(ADC1->CR2&1<<3);  //等待校准结束    
    //该位由软件设置并由硬件清除。在校准寄存器被初始化后该位将被清除。   
 ADC1->CR2|=1<<2;        //开启AD校准   
 while(ADC1->CR2&1<<2);  //等待校准结束
 //该位由软件设置以开始校准,并在校准结束时由硬件清除 
}     
//获得ADC值
//ch:通道值 0~3
u16 Get_Adc(u8 ch)  
{
 //设置转换序列     
 ADC1->SQR3&=0XFFFFFFE0;//规则序列1 通道ch
 ADC1->SQR3|=ch;          
 ADC1->CR2|=1<<22;       //启动规则转换通道
 while(!(ADC1->SR&1<<1));//等待转换结束     
 return ADC1->DR;  //返回adc值 
}

#define ADC_CH0  0 //通道0
#define ADC_CH1  1 //通道1
#define ADC_CH2  2 //通道2
#define ADC_CH3  3 //通道3   
 
void Adc_Init(void);
u16  Get_Adc(u8 ch);  

下载程序后,按下WAIT_UP键,屏幕显示电压有变化。

详情请登录网友——正点原子官方论坛
http://www.openedv.com/forums/list.htm或下载《STM32不完全手册V2.0》
源代码:
实验12 ADC实验.rar


助工
2012-06-03 19:21:01     打赏
64楼
//得到ADC采样内部温度传感器的值
//取10次,然后平均
u16 Get_Temp(void)
{
 u16 temp_val=0;
 u8 t;
 for(t=0;t<10;t++)
 {
  temp_val+=Get_Adc(TEMP_CH);
  delay_ms(5);
 }
 return temp_val/10;
}


#define TEMP_CH  16 //温度传感器通道

详情请登录网友——正点原子官方论坛
http://www.openedv.com/forums/list.htm或下载《STM32不完全手册V2.0》
源代码:
实验13 内部温度传感器实验.rar

助工
2012-06-04 18:48:52     打赏
65楼
我又不是卖这板的,我没有要做广告的意思喔,原以为EEPW要做类似的PCB给我们,所以才搞上去做为共享资料的。

助工
2012-06-04 20:37:01     打赏
66楼
u16 DMA1_MEM_LEN;//保存DMA每次数据传送的长度      
//DMA1的各通道配置
//这里的传输形式是固定的,这点要根据不同的情况来修改
//从存储器->外设模式/8位数据宽度/存储器增量模式
//DMA_CHx:DMA通道CHx
//cpar:外设地址
//cmar:存储器地址
//cndtr:数据传输量 
void MYDMA_Config(DMA_Channel_TypeDef*DMA_CHx,u32 cpar,u32 cmar,u16 cndtr)
{
 u32 DR_Base;  //做缓冲用,不知道为什么.非要不可
 RCC->AHBENR|=1<<0;//开启DMA1时钟
 
delay_us(1);   //开启DMA1时钟后需等待其稳定(这一步一定要,我之前调试一直不行,就是错在这里)
 DR_Base=cpar;  
 DMA_CHx->CPAR=DR_Base;   //DMA1 外设地址
 DMA_CHx->CMAR=(u32)cmar; //DMA1,存储器地址
 DMA1_MEM_LEN=cndtr;      //保存DMA传输数据量
 DMA_CHx->CNDTR=cndtr;    //DMA1,传输数据量
 DMA_CHx->CCR=0X00000000;//复位
 DMA_CHx->CCR|=1<<4;  //从存储器读
 DMA_CHx->CCR|=0<<5;  //普通模式
 DMA_CHx->CCR|=0<<6;  //外设地址非增量模式
 DMA_CHx->CCR|=1<<7;  //存储器增量模式
 DMA_CHx->CCR|=0<<8;  //外设数据宽度为8位
 DMA_CHx->CCR|=0<<10; //存储器数据宽度8位
 DMA_CHx->CCR|=1<<12; //中等优先级
 DMA_CHx->CCR|=0<<14; //非存储器到存储器模式     
}
//开启一次DMA传输
void MYDMA_Enable(DMA_Channel_TypeDef*DMA_CHx)
{
 DMA_CHx->CCR&=~(1<<0);       //关闭DMA传输
 DMA_CHx->CNDTR=DMA1_MEM_LEN; //DMA1,传输数据量
 DMA_CHx->CCR|=1<<0;          //开启DMA传输
}   

详情请登录网友——正点原子官方论坛
http://www.openedv.com/forums/list.htm或下载《STM32不完全手册V2.0》
源代码:
实验14 DMA实验.rar

波特率是9600,认识我的都知道我的所有寄存器操作篇的波特率是9600。

助工
2012-06-04 22:22:19     打赏
67楼
        搞了几天的触摸屏都不行,到最后发现是我的触摸屏坏了,杯具啊!几天的时间都没了!最重要的我都不知道什么时候坏的,不知道谁拿了我的摔烂了(我这里有很多其他人,我后来发现触摸屏有裂痕),又要买液晶屏啦!

高工
2012-06-04 22:51:26     打赏
68楼
LZ的帖子很规范,做得也不少,不错~!

助工
2012-06-06 15:08:42     打赏
69楼
谢啦,继续努力!完成新手入门级寄存器操作编。

助工
2012-06-08 16:57:34     打赏
70楼

myiic.c定义IIC协议:
//初始化IIC
void IIC_Init(void)
{         
  RCC->APB2ENR|=1<<3;//先使能外设IO PORTB时钟        
 GPIOB->CRL&=0X00FFFFFF;//PB6/7 推挽输出
 GPIOB->CRL|=0X33000000;   
 GPIOB->ODR|=3<<6;     //PB6,7 输出高
}
//产生IIC起始信号
void IIC_Start(void)
{
 SDA_OUT();     //sda线输出
 IIC_SDA=1;     
 IIC_SCL=1;
 delay_us(4);
  IIC_SDA=0;//START:when CLK is high,DATA change form high to low
 delay_us(4);
 IIC_SCL=0;//钳住I2C总线,准备发送或接收数据
}  
//产生IIC停止信号
void IIC_Stop(void)
{
 SDA_OUT();//sda线输出
 IIC_SCL=0;
 IIC_SDA=0;//STOP:when CLK is high DATA change form low to high
  delay_us(4);
 IIC_SCL=1;
 IIC_SDA=1;//发送I2C总线结束信号
 delay_us(4);           
}
//等待应答信号到来
//返回值:1,接收应答失败
//        0,接收应答成功
u8 IIC_Wait_Ack(void)
{
 u8 ucErrTime=0;
 SDA_IN();      //SDA设置为输入 
 IIC_SDA=1;delay_us(1);   
 IIC_SCL=1;delay_us(1); 
 while(READ_SDA)
 {
  ucErrTime++;
  if(ucErrTime>250)
  {
   IIC_Stop();
   return 1;
  }
 }
 IIC_SCL=0;//时钟输出0    
 return 0; 
}
//产生ACK应答
void IIC_Ack(void)
{
 IIC_SCL=0;
 SDA_OUT();
 IIC_SDA=0;
 delay_us(2);
 IIC_SCL=1;
 delay_us(2);
 IIC_SCL=0;
}
//不产生ACK应答     
void IIC_NAck(void)
{
 IIC_SCL=0;
 SDA_OUT();
 IIC_SDA=1;
 delay_us(2);
 IIC_SCL=1;
 delay_us(2);
 IIC_SCL=0;
}              
//IIC发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答    
void IIC_Send_Byte(u8 txd)
{                       
    u8 t;  
 SDA_OUT();     
    IIC_SCL=0;//拉低时钟开始数据传输
    for(t=0;t<8;t++)
    {             
        IIC_SDA=(txd&0x80)>>7;
        txd<<=1;   
  delay_us(2);   //对TEA5767这三个延时都是必须的
  IIC_SCL=1;
  delay_us(2);
  IIC_SCL=0; 
  delay_us(2);
    } 
}     
//读1个字节,ack=1时,发送ACK,ack=0,发送nACK  
u8 IIC_Read_Byte(unsigned char ack)
{
 unsigned char i,receive=0;
 SDA_IN();//SDA设置为输入
    for(i=0;i<8;i++ )
 {
        IIC_SCL=0;
        delay_us(2);
  IIC_SCL=1;
        receive<<=1;
        if(READ_SDA)receive++;  
  delay_us(1);
    }     
    if (!ack)
        IIC_NAck();//发送nACK
    else
        IIC_Ack(); //发送ACK  
    return receive;
}

myiic.h:
//IO方向设置
#define SDA_IN()  {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=0X80000000;}
#define SDA_OUT() {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=0X30000000;}

//IO操作函数 
#define IIC_SCL    PBout(6) //SCL
#define IIC_SDA    PBout(7) //SDA 
#define READ_SDA   PBin(7)  //输入SDA

//IIC所有操作函数
void IIC_Init(void);                //初始化IIC的IO口    
void IIC_Start(void);    //发送IIC开始信号
void IIC_Stop(void);      //发送IIC停止信号
void IIC_Send_Byte(u8 txd);   //IIC发送一个字节
u8 IIC_Read_Byte(unsigned char ack);//IIC读取一个字节
u8 IIC_Wait_Ack(void);     //IIC等待ACK信号
void IIC_Ack(void);     //IIC发送ACK信号
void IIC_NAck(void);    //IIC不发送ACK信号

void IIC_Write_One_Byte(u8 daddr,u8 addr,u8 data);
u8 IIC_Read_One_Byte(u8 daddr,u8 addr); 


24Cxx.c定义24C02系列芯片:
//初始化IIC接口
void AT24CXX_Init(void)
{
 IIC_Init();
}
//在AT24CXX指定地址读出一个数据
//ReadAddr:开始读数的地址 
//返回值  :读到的数据
u8 AT24CXX_ReadOneByte(u16 ReadAddr)
{     
 u8 temp=0;                         
    IIC_Start(); 
 if(EE_TYPE>AT24C16)
 {
  IIC_Send_Byte(0XA0);    //发送写命令
  IIC_Wait_Ack();
  IIC_Send_Byte(ReadAddr>>8);//发送高地址    
 }else IIC_Send_Byte(0XA0+((ReadAddr/256)<<1));   //发送器件地址0XA0,写数据    
 IIC_Wait_Ack();
    IIC_Send_Byte(ReadAddr%256);   //发送低地址
 IIC_Wait_Ack();    
 IIC_Start();       
 IIC_Send_Byte(0XA1);           //进入接收模式     
 IIC_Wait_Ack(); 
    temp=IIC_Read_Byte(0);    
    IIC_Stop();//产生一个停止条件    
 return temp;
}
//在AT24CXX指定地址写入一个数据
//WriteAddr  :写入数据的目的地址   
//DataToWrite:要写入的数据
void AT24CXX_WriteOneByte(u16 WriteAddr,u8 DataToWrite)
{                               
    IIC_Start(); 
 if(EE_TYPE>AT24C16)
 {
  IIC_Send_Byte(0XA0);     //发送写命令
  IIC_Wait_Ack();
  IIC_Send_Byte(WriteAddr>>8);//发送高地址  
 }else IIC_Send_Byte(0XA0+((WriteAddr/256)<<1));   //发送器件地址0XA0,写数据  
 IIC_Wait_Ack();   
    IIC_Send_Byte(WriteAddr%256);   //发送低地址
 IIC_Wait_Ack();                   
 IIC_Send_Byte(DataToWrite);     //发送字节         
 IIC_Wait_Ack();           
    IIC_Stop();//产生一个停止条件
 delay_ms(10); 
}
//在AT24CXX里面的指定地址开始写入长度为Len的数据
//该函数用于写入16bit或者32bit的数据.
//WriteAddr  :开始写入的地址 
//DataToWrite:数据数组首地址
//Len        :要写入数据的长度2,4
void AT24CXX_WriteLenByte(u16 WriteAddr,u32 DataToWrite,u8 Len)
{   
 u8 t;
 for(t=0;t<Len;t++)
 {
  AT24CXX_WriteOneByte(WriteAddr+t,(DataToWrite>>(8*t))&0xff);
 }               
}

//在AT24CXX里面的指定地址开始读出长度为Len的数据
//该函数用于读出16bit或者32bit的数据.
//ReadAddr   :开始读出的地址
//返回值     :数据
//Len        :要读出数据的长度2,4
u32 AT24CXX_ReadLenByte(u16 ReadAddr,u8 Len)
{   
 u8 t;
 u32 temp=0;
 for(t=0;t<Len;t++)
 {
  temp<<=8;
  temp+=AT24CXX_ReadOneByte(ReadAddr+Len-t-1);         
 }
 return temp;               
}
//检查AT24CXX是否正常
//这里用了24XX的最后一个地址(255)来存储标志字.
//如果用其他24C系列,这个地址要修改
//返回1:检测失败
//返回0:检测成功
u8 AT24CXX_Check(void)
{
 u8 temp;
 temp=AT24CXX_ReadOneByte(255);//避免每次开机都写AT24CXX     
 if(temp==0X55)return 0;    
 else//排除第一次初始化的情况
 {
  AT24CXX_WriteOneByte(255,0X55);
     temp=AT24CXX_ReadOneByte(255);  
  if(temp==0X55)return 0;
 }
 return 1;            
}

//在AT24CXX里面的指定地址开始读出指定个数的数据
//ReadAddr :开始读出的地址 对24c02为0~255
//pBuffer  :数据数组首地址
//NumToRead:要读出数据的个数
void AT24CXX_Read(u16 ReadAddr,u8 *pBuffer,u16 NumToRead)
{
 while(NumToRead)
 {
  *pBuffer++=AT24CXX_ReadOneByte(ReadAddr++); 
  NumToRead--;
 }

//在AT24CXX里面的指定地址开始写入指定个数的数据
//WriteAddr :开始写入的地址 对24c02为0~255
//pBuffer   :数据数组首地址
//NumToWrite:要写入数据的个数
void AT24CXX_Write(u16 WriteAddr,u8 *pBuffer,u16 NumToWrite)
{
 while(NumToWrite--)
 {
  AT24CXX_WriteOneByte(WriteAddr,*pBuffer);
  WriteAddr++;
  pBuffer++;
 }
}

24cxx.h定义函数:
#define AT24C01  127
#define AT24C02  255
#define AT24C04  511
#define AT24C08  1023
#define AT24C16  2047
#define AT24C32  4095
#define AT24C64     8191
#define AT24C128 16383
#define AT24C256 32767 
//Mini STM32开发板使用的是24c02,所以定义EE_TYPE为AT24C02
#define EE_TYPE AT24C02
      
u8 AT24CXX_ReadOneByte(u16 ReadAddr);       //指定地址读取一个字节
void AT24CXX_WriteOneByte(u16 WriteAddr,u8 DataToWrite);  //指定地址写入一个字节
void AT24CXX_WriteLenByte(u16 WriteAddr,u32 DataToWrite,u8 Len);//指定地址开始写入指定长度的数据
u32 AT24CXX_ReadLenByte(u16 ReadAddr,u8 Len);     //指定地址开始读取指定长度数据
void AT24CXX_Write(u16 WriteAddr,u8 *pBuffer,u16 NumToWrite); //从指定地址开始写入指定长度的数据
void AT24CXX_Read(u16 ReadAddr,u8 *pBuffer,u16 NumToRead);    //从指定地址开始读出指定长度的数据

u8 AT24CXX_Check(void);  //检查器件
void AT24CXX_Init(void); //初始化IIC

详情请登录网友——正点原子官方论坛
http://www.openedv.com/forums/list.htm或下载《STM32不完全手册V2.0》
源代码:
实验15 IIC实验.rar

KEY0=USER BUTTON ; 
KEY1=Anti_tamper; 
KEY2=WAKEup;




共78条 7/8 |‹ 3 4 5 6 7 8 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]