⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 midialarm.c

📁 一个用C语言开发AVR单片机音乐播放器程序
💻 C
📖 第 1 页 / 共 2 页
字号:
	              TWCR = ()
	              break; 
	  case 0x70 : twi_flag = 0;
	              break;
	  case 0x78 : twi_flag = 0;
	              break;
	  default : twi_init();
	            TWCR = (1<<TWIE) | (1<<TWEN) ;  
	            return 0;
   }
   TWCR = (1<<TWINT) | (1<<TWEA);  //ACK
   
   twi_count = 0;   //初始化计数器
   while(1)
   {
      TWCR |= (1<<TWINT);   //清零中断标志位
	  j = 0;
	  while(!(TWCR & (1<<TWINT)) && j <= 10000){j++;}
	  if(j>10000)
	  {
	     twi_init();
	     TWCR = (1<<TWIE) | (1<<TWEN) ; 
	     return 0;
      } 
	  switch(TWSR & 0xF8)
	  {
	     case 0x80 : twi_flag = 0;
		             break;
		 case 0x88 : twi_flag = 1;
		             break;
		 case 0x90 : twi_flag = 0;
		             break;
		 case 0x98 : twi_flag = 1;
		             break;
		 case 0xA0 : twi_flag = 0;
		             TWCR |= (1<<TWINT);
					 I2cRnum = twi_count;  //记录收到的字节数 
					 return twi_count;
		 default : twi_init();
	               TWCR = (1<<TWIE) | (1<<TWEN) ; 
	               return 0;
	  }
	  if(twi_flag)
	  {
	     twi_init();
	     TWCR = (1<<TWIE) | (1<<TWEN) ; 
	     return 0;
	  }
	  
	  I2cRbuf[twi_count] = TWDR;   //将接收到的数据存入i2c接收缓存
	  twi_count++;
	  if(twi_count>8)
		 break;
   } 
   return twi_count;   
}*/

/***********************************************
总线上启动开始条件程序:twi_start()   返回值 1:发送成功 0:发送失败
***********************************************/
uchar twi_start()          
{
   uchar twi_flag,n;
   uint j;
   
   n = 0;
   twi_flag = 1;   // 1:defeat  0:success
   while(twi_flag)
   {
      n++;
	  if(n>5)
	  {
	     twi_init();
		 TWCR = (1<<TWEA) | (1<<TWEN);
		 return 0;
	  } 
	  
	  TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTA);   //发送起始电平
      j=0;
      while(!(TWCR&(1<<TWINT)) && j<=10000){j++;}
      if(j>10000)
      {
         twi_init();
	     TWCR = (1<<TWEA) | (1<<TWEN);
	     return 0;
      }
   
      switch(TWSR & 0xF8)
      {
         case 0x08 : twi_flag = 0;  
		             break;   //发送起始位成功
	     case 0x10 : twi_flag = 0;
		             break;   
	     case 0x38 : twi_flag = 1;
		             break;  
	     default : twi_init();
	               TWCR = (1<<TWEA) | (1<<TWEN);
				   return 0;		        
      }
	  if(!twi_flag)
	     return 1;
   }	
   return 0;  
}

/***********************************************
总线上启动停止条件程序:twi_stop()
***********************************************/
void twi_stop()
{
   TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);
   DelayMs(10);
}

/*****************************************************
AVR通过I2C总线向AT24C512写数据(字节写): twi_writebyte
*****************************************************/
uchar twi_writebyte(uchar wrdata)
{
   uchar twi_flag,n;
   uint j;
   
   twi_flag = 1;
   n = 0;
   
   while(twi_flag)
   {
      n++;
	  if(n>100)
	  {
	     twi_init();
		 TWCR = (1<<TWEA) | (1<<TWEN);
		 return 0;
	  }
	  
	  TWDR = wrdata;
	  TWCR = (1<<TWINT) | (1<<TWEN);
	  j = 0;
	  while(!(TWCR&(1<<TWINT)) && j<=10000){j++;}
	  if(j>10000)
	  {
	     twi_init();
		 TWCR = (1<<TWEA) | (1<<TWEN);
		 return 0;
	  }
	  
	  switch(TWSR & 0xF8)
	  {
	     case 0x18 : twi_flag = 0;  //发送从设备写,收到应答
		             break;
		 case 0x20 : twi_flag = 1;
		             break;
		 case 0x28 : twi_flag = 0;  //发送数据,收到应答
		             break;		 
		 case 0x30 : twi_flag = 1;
		             break;
		 case 0x38 : twi_flag = 1;
		             break;
		 case 0x40 : twi_flag = 0;  //发送从设备读,收到应答
		             break;
		 case 0x48 : twi_flag = 1;
		             break;
	     default : //usart_txc(TWSR&0xF8);
		           twi_init();
		           TWCR = (1<<TWEA) | (1<<TWEN); 
				   return 0;
	  }
	  if(!twi_flag)
	     return 1;
   }
   return 0;
}

/***********************************************
AVR通过I2C从AT24C512读一个字节程序: twi_readbyte
***********************************************/
uchar twi_readbyte(uchar redata, uchar ack)  //true为ack  false为nack
{
   uchar temp,j;
   temp = 0;
   temp = (1<<TWINT) | (1<<TWEN);
   if(ack)                  
      temp |= (1<<TWEA);
	  
   TWCR = temp;
   j=0;
   while(!(TWCR&(1<<TWINT)) && j<=10000){j++;}
   if(j>10000)
   {
      twi_init();
	  TWCR = (1<<TWEA) | (1<<TWEN);
	  return 0;
   } 
   
   redata = TWDR;
   usart_txc(redata);
   switch(TWSR & 0xF8)
   {
      case 0x38 : return 0;
	  case 0x50 : return 1;
	  case 0x58 : return 1;
	  default : //usart_txc(TWSR&0xF8);
	            twi_init();
	            TWCR = (1<<TWEA) | (1<<TWEN);
				return 0;
   }
}

/*************************************************
写数据 AT24c512Write()
Devaddr 设备地址  addr_h 高位地址  addr_l 低位地址
w_data 需写入的数据 num_w 数据长度 
*************************************************/
uchar AT24c512Write(uchar Devaddr, uchar addr_h, uchar addr_l, uchar w_data)
{
   uchar temp1,k=0;
   
   while(!twi_start() && k<=10){k++;}     //发送起始电平
   if(k>10)
      return 0;  //返回失败(0)
   
   temp1 = 0xA0 | (Devaddr<<1);  //设备地址写
   k=0;
   while(!twi_writebyte(temp1) && k<=10){k++;}
   if(k>10)
      return 0;
   
   k=0;
   while(!twi_writebyte(addr_h) && k<=10){k++;}   //写高位地址
   if(k>10)
      return 0;   
	  
   k=0;
   while(!twi_writebyte(addr_l) && k<=10){k++;}   //写低位地址
   if(k>10)
      return 0;
	  
   k=0;
   while(!twi_writebyte(w_data) && k<=10){k++;}   //写数据
   if(k>10)
      return 0;
	  
   twi_stop();   //发送停止位
   return 1;     //写数据完成,返回成功(1)
}

/********************************************************
读数据  AT24c512Read()
Devaddr 设备地址   addr_h  高位地址   addr_l   低位地址
r_data  读出的数据  num_r  数据长度
********************************************************/
uchar AT24c512Read(uchar Devaddr, uchar addr_h, uchar addr_l,uchar r_data)
{
   uchar temp2,k=0;
   
   while(!twi_start() && k<=10){k++;}  //启动起始条件
   if(k>10)
      return 0;
	  
   temp2 = 0xA0 | (Devaddr<<1);      //设备地址写  
   k=0;
   while(!twi_writebyte(temp2) && k<=10){k++;}
   if(k>10)
      return 0;
	  
   k=0;
   while(!twi_writebyte(addr_h) && k<=10){k++;}   //高位地址
   if(k>10)
      return 0;
	  
   k=0;
   while(!twi_writebyte(addr_l) && k<=10){k++;}   //低位地址
   if(k>10)
      return 0;
	  
   k=0;
   while(!twi_start() && k<=10){k++;}  //启动起始条件
   if(k>10)
      return 0;
	  
   temp2 = 0xA1 | (Devaddr<<1);     //设备地址读
   k=0;
   while(!twi_writebyte(temp2) && k<=10){k++;}
   if(k>10)
      return 0;
	
   k=0;
   while(!twi_readbyte(r_data,0) && k<=10){k++;}   //读数据
   if(k>10)
      return 0;  
	  
   twi_stop();
   return 1;   
}

/***********************************************
timer_init(): 定时器T0,T1初始化
功能:初始化T0,T1;T0
***********************************************/
void timer_init()
{
    TCCR1A = 0x00;   //工作在普通端口模式
	TCCR1B = 0x08;   //T1工作在CTC方式,初始化时先令T1的输出比较不工作
    TCCR0 = 0x00;    //先令T0不工作
	TCNT0 = 0x16;    //设置T0初始值,1/400节拍为1870us
	TCCR2 = 0x00;    //先令T2不工作
	TCNT2 = 0x07;    //设置T2初值,每产生一次溢出中断时间为2000us
	TIMSK = 0x51;    //使能T0溢出中断,T1输出比较中断, T2溢出中断
}

/******************************
can总线初始化函数
******************************/
void can_init()//can 初始化
{
    uchar *p_canaddr;
    uchar i,j;
	/*for(i=0;i<20;i++)
	for(j=0;j<8;j++)
	canRbuf[i][j]=0;*/
    CAN_CS_0;
	CAN_RST_0;
	DelayMs(5);
	CAN_RST_1;
    
    //硬件复位首先进入BasicCAN mode
    
    //进入复位mode(控制寄存器CR)
    p_canaddr = (uchar *)CAN_OFFSET;//CAN0
    while((*p_canaddr & 0x01) != 0x01)
    {
        *p_canaddr = 0x01;  //(0)RR=1;关中断
    }
    
    //choose PeliCAN mode(时钟分频寄存器CDR)
    p_canaddr = (uchar *)(CAN_OFFSET + 31);//CAN 31
    do{
        *p_canaddr = 0xcf;//(7)can mode=1:PeliCAN; (6)CBP=1:中止输入比较器; 
		//(5)RXINTEN=0;(3)关闭时钟=1:CLK无效;(2:0)CD2:0=111(fosc)
    }while(*p_canaddr != 0xcf);
    
    //设置验收滤波器(包括验收代码寄存器ACRn 和 验收屏蔽寄存器AMRn)
    p_canaddr = (uchar*)CAN_OFFSET;//CAN0
    for(i=0;i<8;i++)
      *(p_canaddr + 16 + i) = 0xff;//ACR=0XFF;AMR=0XFF;
    //完全接受
    *(p_canaddr + 19) = can_laddr<<3;//local address load into ACR3(ID28:21)
    *(p_canaddr + 23) &= 0x07;//AMR3 enable ACR3 to compare data input
    
    //总线定时寄存器1,0(BTR1,0)
	//每位时钟频率:fOSC/4*(4+7+1)
    p_canaddr = (uchar*)(CAN_OFFSET + 6);//can 6:BTR0
    //*p_canaddr = 0x47;
	*p_canaddr = 0xC1;
	//(7:6)SJW1..0=11同步跳转宽度tSJW=4tSCL;
	//(5:0)BRP(5:0)=000001波特率预设值can系统时钟fSCL = fOSC/4; 
    //*(p_canaddr + 1) = 0XA5;
	*(p_canaddr + 1) = 0x17;
	//CAN 7 BTR1:(7)SAM=0:单倍采样;
	//(6:4)TSEG2(2:0)=001 TSEG2=1tSCL; (3:0)TSEG1(3:0)=0111 tSEG1=7tSCL;    
    
	//输出控制寄存器(OCR)
    p_canaddr = (uchar*)(CAN_OFFSET + 8);//CAN 8
    *p_canaddr = 0XDA;//T1未用 (1:0)OCMODE(1:0)=10正常OUT MODE
    
	//中断使能寄存器(IER)
	p_canaddr = (uchar*)(CAN_OFFSET + 4);//CAN 4
    *p_canaddr = 0x01;//RIE=1 开接收中断
	
    //进入工作 mode , 单验收滤波器
    p_canaddr = (uchar*)CAN_OFFSET;//CAN 0
    do{
        *p_canaddr = 0x08;//(3)AFM=1单滤波器MODE;(0)RM=0:工作MODE
    }while(*p_canaddr != 0x08);
    
    //使能SRAM中断INT2
   // EIMSK |= (1<<INT2);
}

/********************************************
can发送程序(标准帧)
can_Saddr:目的地址  canSndbuf[8]:发送缓存区
nums发送字节数
********************************************/
uchar can_sends(uchar Saddr, uchar nums )   
{
    uchar i;
	uchar *p_canaddr;
	
	if(nums>8)
	   nums = 8;
	p_canaddr = (uchar*)(CAN_OFFSET + 2 );  //CAN 2 状态寄存器
	if((*p_canaddr & 0x04) == 0x04)  //查询发送缓存区状态是否为空(TBS?=1)
	{
	   p_canaddr = (uchar*)(CAN_OFFSET + 16);   //CAN 16 帧信息
	   *p_canaddr = (0x0f & nums); //FF(7)=0标准帧,RTR(6)=0数据帧,DLC3~0(3~0)=1000数据长度=8
	   p_canaddr++;    //can 17 
	   *p_canaddr = (Saddr >> 3);  //目的地址
	   p_canaddr++;    //can 18
	   *p_canaddr = (Saddr << 5);
	   for(i=0; i<nums; i++)   //发送数据
	   {
	      p_canaddr++;   //can 19~26
		  *p_canaddr = canSndbuf[i];
		  //usart_txc(canSndbuf[i]);     //调试时比对can和usart发送的数据
	   }
	   p_canaddr = (uchar*)(CAN_OFFSET + 1);   //can 1 命令寄存器
	   *p_canaddr = 0x01;    //发送请求
	   return 1;
	}
	else
	   return 0;
}

/*********************************************
发送程序(扩展帧)
can_Saddr:目的地址  canSndbuf[8]:发送缓存区
nume发送字节数
*********************************************/
/*uchar can_sende(uchar Saddr,uchar nume)
{
    uchar i;
	uchar *p_canaddr;
	
	if(nume>8)
	   nume = 8;
	p_canaddr = (uchar*)(CAN_OFFSET + 2);  //CAN 2  状态寄存器
	if((*p_canaddr & 0x04) == 0x04)   //查询发送缓存区状态是否为空(TBS?=1)
	{
	   p_canaddr = (uchar*)(CAN_OFFSET + 16);  //CAN 16 帧信息
	   *p_canaddr = (0x0F & nume) | 0x80;  //FF(7)=1扩展帧,RTR=0数据帧,DLC3~0=1000数据长度
	   p_canaddr++;//can 17 ID28-21
       *p_canaddr = can_laddr;//本机地址 Saddr >> 3;
       p_canaddr++;//can18 ID20-13
	   *p_canaddr = comm;//命令号 
	   p_canaddr++;//can19 ID12=0 uend,ID12=1 end; ID11-5:帧计数
	   *p_canaddr = 0x80;//命令号
	   p_canaddr++;//can20 ID4-0 目的地址
	   *p_canaddr = Saddr << 3;
	   
	   for(i=0;i<nume;i++)//can 21..28 发送数据
        {
            p_canaddr++;
            *p_canaddr = canSbuf[i];
			USART_Transmit(canSbuf[i]);
        }
        p_canaddr = (uchar*)(CAN_OFFSET + 1);//CAN 1
        *p_canaddr = 0x01;//发送请求
        return 1;
	}
	else 
	   return 0;
}*/

/********************************************
can总线接收中断服务程序

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -