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

📄 com.c

📁 STM32 单片机例程
💻 C
字号:
#include "..\main\include.h"
//#include "include.h"
/**************************************************************************************
* 变量原型:
* 变量说明:    
**************************************************************************************/
/**************************************************************************************
* 函数原型:
* 函数功能:
* 输入参数:
* 输出参数:
* 函数说明:
**************************************************************************************/
#define USART1_RXNEirqEnable()    USART1->CR1 |= USART_FLAG_RXNE     //打开串口1接收中断
#define USART1_RXNEirqUnable()    USART1->CR1 &= ~USART_FLAG_RXNE    //关闭串口1接收中断

#define USART1_TXEirqEnable()    USART1->CR1 |= USART_FLAG_TXE     //打开串口1发送中断
#define USART1_TXEirqUnable()    USART1->CR1 &= ~USART_FLAG_TXE    //关闭串口1发送中断

#define USART1_TCirqEnable()     USART1->CR1 |= USART_FLAG_TC      //打开串口1发送完毕中断
#define USART1_TCirqUnable()     USART1->CR1 &= ~USART_FLAG_TC     //关闭串口1发送完毕中断

struPROTOCOL_Receive Receive;
struPROTOCOL_Send Send;


uint8* pRev;
uint8* pSend;

uint16 LocalAddr;   //本机地址


void SetLocalAddr(uint16 temp)//本机地址
{
   LocalAddr = temp;
}


//struPROTOCOL_Receive *getReceive(void)
//{
//   return(&Receive);
//}

/*
功能:返回发送数据启始地址
注意:不含数据包的帧头信息
*/
uint8* getSendBuf(void)
{
   while (Send.start != NO_SEND);  //如果上一包数据没发送完将等待....
   return(Send.buf);
}

/*
功能:返回接收数据启始地址
注意:
1、应该先判断接收到的数据包是请求还是应答
2、不含数据包的帧头信息
3、如果是应答不含状态信息
*/
uint8* getReceiveBuf(void)
{
   return(Receive.buf);
}


//返回功能号
uint16 getCmd(void)
{
   return(Receive.header.cmd);
}


/*
功能:检查接收数据包有没完成
返回值:

0=收到数据并且校验成功
1=收到数据并且校验失败

255=没收到数据

*/
uint8 testReceiveOver(void)
{
   uint16 chk;

   if (Receive.start == RECEIVE_OVER)//整个协议包接收完毕
   {
      PC_RS485Send_Enable(); //切换RS485到发送状态
      
      //swp16HL(&Receive.header.chk);//协议包校验
      chk = Check_Sum(Receive.buf - FRAME_HEADER_LEN, Receive.rrLen);
      if (chk != 0)//校验错误
      {
         init_Receive();
         return(1);
      }
      else//校验正确
      {
          swp16HL(&Receive.header.chk);//协议包校验.实际已经无用
          swp16HL(&Receive.header.tLen);//协议包总长度
          swp16HL(&Receive.header.object_addr);//目的地址
          swp16HL(&Receive.header.cmd);//命令
          
          if(Receive.header.object_addr == LocalAddr ||
             Receive.header.object_addr == 0xffff)//地址相同||广播地
          {
             return(0);
          }
          else
          {
             init_Receive();
             return(1);
          }
      }
   }
   else
   {
      return(255);
   }
}


//初始化接收
void init_Receive(void)
{
   Receive.start = NO_HEADER; //接收到头标志.还没收到头
   Receive.rLen = 0;     //接收数据量

   Receive.header.chk = 0;   //协议包校验
   Receive.header.tLen = 0;      //协议包总长度
   Receive.header.object_addr = LocalAddr; //目的地址
   Receive.header.cmd = 0;      //命令

   pRev = Receive.buf-FRAME_HEADER_LEN;//header;//接收数据指针
   
}


//初始化发送
void init_Send(void)
{
   Send.sLen = 0;
   Send.start = NO_SEND;   //还没开始发送数据
   
   Send.header.object_addr = LocalAddr; //目的地址


   pSend = Send.buf - FRAME_HEADER_LEN;  //发送数据指针
}

/**************************************************************************************
* 函数原型:void InitCom(void)
* 函数功能:清空接收和发送缓冲区,初始化串口,设置波特率
* 输入参数:
* 输出参数:
* 函数说明:
**************************************************************************************/
void InitCom(void)
{
   init_Receive();
   init_Send();
}


/*
在调用SendFun(),将判断前一次的数据包有没发送完毕

*/
void SendFun(void)
{
   //while(send.start==START_SEND);  //如果上一包数据没发送完将等待....

 #ifdef PC_RS485//只有485芯片才延时,使用CAN芯片不延时
   //Delayus(500);
   Wait_ms(1);
 #endif  
   
   Send.header.tLen += FRAME_HEADER_LEN; //数据包长度=数据长度+帧头长度
   Send.sLen = Send.header.tLen; //发送数据长度
   
   swp16HL(&Send.header.tLen);//协议包总长度
   swp16HL(&Send.header.object_addr);//目的地址
   swp16HL(&Send.header.cmd);//命令
   
   pSend=Send.buf-FRAME_HEADER_LEN;             //复位发送数据指针。注意:前2byte是校验
   Send.header.chk=Check_Sum( pSend+2, Send.sLen-2 );  //计算校验和。注意:不能计算校验位
   swp16HL(&Send.header.chk);//协议包校验
   
   Send.start = START_SEND;//开始发送
   USART1_TXEirqEnable(); //TI = 1;
}


//等待前一包数据发送完成
void  WaitSendOver(void)
{
   while (Send.start != NO_SEND);  //如果上一包数据没发送完将等待....
}


//发送应答
void SendFunAck(uint16 len)
{
   
   while (Send.start != NO_SEND);  //如果上一包数据没发送完将等待....

   Send.header.tLen = len;

   Send.header.object_addr = LocalAddr; //目的地址=接收到的源地址
   Send.header.cmd = Receive.header.cmd;
   SendFun();
}


/*
本程序是在中断中转换关键字的,占用CPU时间(中断时间长),但节省空间,对内存不足的系统采用该方式
对于内存大的系统,不在中断中转换关键字,但内存必须是接受数据的2倍,以保证所有数据都是关键字的最坏情况
*/
void isrReceive(void)
{uint8 ch;
 
   
   ch = (USART1->DR & 0x1FF);

   if (Receive.start == RECEIVE_OVER) //整个协议包接收完毕, 如果还没处理丢掉该数据
   {
      return;
   }

   if (ch == SEND_HEADER && Receive.start==NO_HEADER)//?   {
      init_Receive();
      Receive.start = RECEIVE_DATA;//已经收到头,开始接收数据
   }
   else//数据
   {
      if (Receive.start == RECEIVE_DATA)//已经收到头,开始接收数据
      {
         
         Receive.rLen++;
         
         if( Receive.rLen >= (FRAME_HEADER_LEN+RECEIVE_BUFF_SIZE) )//数据缓冲已经用完,仍然没收到完整的数据包
         {//说明多半是数据掉包造成的,或者接收到错误的数据长度
            init_Receive();//
            return;
         }
         
         *pRev++=ch;
          
         if(Receive.rLen==4)//协议包总长度收完//if(receive.rLen==FRAME_HEADER_LEN)//头收完
         {
            Receive.rrLen=Receive.header.tLen;
            swp16HL(&Receive.rrLen);//协议包总长度
         }
         else if(Receive.rLen>4 && Receive.rLen==Receive.rrLen)//数据接收完毕
         {
            //校验和地址判断不在此函数里判断
            Receive.start=RECEIVE_OVER;//整个协议包接收完毕
         }
      }
   }
}



/*
//中断中调用发送
本程序是在中断中转换关键字的,占用CPU时间(中断时间长),但节省空间,对内存不足的系统采用该方式
对于内存大的系统,不在中断中转换关键字,但内存必须是接受数据的2倍,以保证所有数据都是关键字的最坏情况
*/
void isrSend(void)
{
   uint8 ch; 

   if (Send.sLen == 0)//数据发送完毕
   {
      //PC_RS485Receive_Enable();//切换RS485到接收状态
      //这里数据仍然没发送出去,应该判断TC标志,这里用中断实现
      USART1_TCirqEnable();//打开串口1发送完毕中断
      
      Send.start = NO_SEND;//发送完毕
      USART1_TXEirqUnable();  // disable TX interrupt if nothing to send
      //USART1_TCirqUnable();
   }
   else
   {
      ch = *pSend;
      if (Send.start == START_SEND)//开始发送.还没发送数据
      {
         USART1->DR = SEND_HEADER; //发送数据头//SBUF = SEND_HEADER; //发送数据头
         Send.start = SEND_DATA;
      }
      else
      {
         USART1->DR = ch;//SBUF = ch;
         pSend++;
         Send.sLen--;
      }
   }
}

/**************************************************************************************
* 函数原型:void USART1_IRQHandler(void)
* 函数功能:串口中断服务程序
* 输入参数:
* 输出参数:
* 函数说明:
**************************************************************************************/
/*----------------------------------------------------------------------------
  USART1_IRQHandler
  Handles USART1 global interrupt request.
 *----------------------------------------------------------------------------*/
//void USART1_IRQHandler(void)
void USART1_IRQFun(void)
{
   volatile unsigned int IIR;
   

   IIR = USART1->SR;
   if (IIR & USART_FLAG_RXNE)
   {
      if(Send.start == NO_SEND)//发送完毕//使用CAN芯片做485才做此判断
      {
         // read interrupt
         USART1->SR &= ~USART_FLAG_RXNE;    // clear interrupt
         
         isrReceive();
      }
   }

   if( (IIR & USART_FLAG_TXE) && Send.start != NO_SEND )
   {
      USART1->SR &= ~USART_FLAG_TXE;     // clear interrupt//实际对USART_DR的写操作,将该位清零
      isrSend();
   }
   
   if( (IIR & USART_FLAG_TC)&& Send.start == NO_SEND )
   {
      USART1->SR &= ~USART_FLAG_TC;     // clear interrupt
      USART1_TCirqUnable();
      PC_RS485Receive_Enable();//切换RS485到接收状态
      //isrSend();
   }
   
}

void sendchar (int ch)
{
    while (!(USART1->SR & USART_FLAG_TXE));
    USART1->DR = (ch & 0x1FF);
    //while (!(USART1->SR & USART_FLAG_TC));
}

void DebugSendBuf(uint8* buf, uint32 len)
{uint32 USART1_irq;
	
	 
	 USART1_irq=USART1->CR1;//保存串口中断状态
	 
	 PC_RS485Send_Enable();//如果定义PC_RS485CAN,这里关闭了串口接收中断
 
 #ifdef PC_RS485//只有485芯片才延时,使用CAN芯片不延时
   Wait_ms(1);
 #endif  
	 
	 USART1_TXEirqUnable();
	 USART1_TCirqUnable();
	 
   
   while (len)
   {
      sendchar(*buf++);
      len--;
      
      //Watchdog();
   }

   //恢复串口中断允许
   //USART1->CR1 |= (USART1_irq&(USART_FLAG_TXE|USART_FLAG_TC));
   USART1->CR1 |= (USART1_irq&(USART_FLAG_TXE | USART_FLAG_TC | USART_FLAG_RXNE));
}


void USART1_InitConfig(uint32 BaudRate)
{USART_InitTypeDef USART_InitStructure;
  
  //USART1->SR &= ~USART_FLAG_TXE;     // clear interrupt
  //USART1->SR &= ~USART_FLAG_TC;     // clear interrupt
  
  USART_InitStructure.USART_BaudRate = BaudRate;
  USART_InitStructure.USART_WordLength = USART_WordLength_8b;
  USART_InitStructure.USART_StopBits = USART_StopBits_1;
  USART_InitStructure.USART_Parity = USART_Parity_No;
  USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;

  /* Configure USART1 */
  USART_Init(USART1, &USART_InitStructure);
  /* Enable USART1 Receive and Transmit interrupts */
  USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
  //USART_ITConfig(USART1, USART_IT_TXE, ENABLE);//发送时才打开
  /* Enable the USART1 */
  USART_Cmd(USART1, ENABLE);//仿真看到执行这里,TC标志居然被设置为1了,不知道实际在flash中运行是否是这样
  
  USART1->SR &= ~USART_FLAG_TXE;     // clear interrupt
  USART1->SR &= ~USART_FLAG_TC;     // clear interrupt
  
//  /* Configure USART2 */
//  USART_Init(USART2, &USART_InitStructure);
//  /* Enable USART2 Receive and Transmit interrupts */
//  USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
//  USART_ITConfig(USART2, USART_IT_TXE, ENABLE);
//  /* Enable the USART2 */
//  USART_Cmd(USART2, ENABLE);
}

⌨️ 快捷键说明

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