通过软件程序消除单片机由外界干扰产生的异常复位的影响(基于STM8S105单片机)

来源:互联网 发布:韦德2016季后赛数据 编辑:程序博客网 时间:2024/05/16 17:45

前言:

首先简单介绍一下外界干扰对单片机的2点影响:

(1)异常复位

在刚上电或外部复位引脚为复位电平时,单片机系统进入一个预定的状态——复位状态。在复位状态下,控制寄存器的值是确定的,而数据寄存器的值是随机的,程序计数器也被赋予一个确定的值。但多数情况下控制寄存器的初始值并非我们需要的,不确定的数据寄存器的值也是无法使用的,需要初始化把它们设置成一个预期的、确定的且安全的状态。初始化完成后,系统进入待命状态。系统在工作过程中,因来自电源的干扰,也可能执行复位操作,称为异常复位,这时如不采取措施,记录工作过程的数据又会被初始化,从而造成异常停机。

(2)程序跑飞

所谓程序跑飞是程序没按预定的顺序执行。因为单片机执行了不该执行的指令,该指令一旦执行,系统的状态就发生改变且不能自动恢复,这时,系统处于失控制状态。


问题分析:

这里我们主要针对STM8S105系列单片机提出一种软件抗干扰的措施:

        存在问题:使用STM8S105单片机控制电机正反转工作时,继电器的吸合和断开会对单片机产生电磁波干扰,使得单片机出现异常复位情况,造成系统停机。通过示波器检测单片机VCC,发现在继电器动作瞬间会对VCC产生较大冲击。

        解决方案:(1)硬件:合理布板;退耦、滤波以及隔离;加屏蔽(针对强电磁干扰下)

                            (2)软件:由于控制系统是通过计时器和外部端口的状态变化来驱动系统工作的,并通过数据寄存器记录工作过程,如果在异常复位的前后我们能保护记录工作过程的数据不变,在复位后系统就会继续工作,如同没发生过干扰一样。故我们应该将程序运行过程中的数据保存在数据寄存器中记录下当前运行位置。


解决过程:

(1)判断单片机是否产生EMS复位

        STM8S105单片机为了避免由电磁干扰造成的对应用程序误写操作或系统挂起,大多数关键寄存器都有一个互补寄存器与之相对应。系统将会自动检测这些关键寄存器与其互补寄存器之间是否匹配。如果不匹配,则产生一个EMS复位,从而使应用程序恢复到正常操作。

        如何判断单片机是EMS复位还是其他情况的复位(STM8S系列单片机有9个复位源):

        通过IAR开发环境在线调试程序,观察当单片机受干扰复位时,复位状态寄存器(RST_SR)各个位的状态值。当位4置1时说明产生了EMC复位。 

            

                      

 (2)配置相关数据寄存器用于保存项目程序运行中的数据

        STM8S105系列单片机中有最多32K字节Flash和多达1K字节真正的数据EEPROM,可以保证数据在掉电后不丢失。这里我们采用EEPROM存储数据。

  数据EEPROM(DATA)区域可用于存储用户具体项目所需的数据。默认情况下,DATA区域是写保护的,这样可以在主程序工作在IAP模式时防止DATA区域被无意地修改。只有使用特定的MASS密钥才能对DATA区域的写保护解锁。

  相关程序:

chipeeprom.h头文件:

#ifndef _chipeeprom_h_
#define _chipeeprom_h_
/* 说明:主芯片STM8S105C4T6*/
/* 自定义宏 */
extern void WriteMultiBlockByte(u8 BlockStartAddress,FLASH_MemType_TypeDef

      FLASH_MemType, FLASH_ProgramMode_TypeDefFLASH_ProgMode, uint8_t *Buffer,uint8_t BlockNum);
extern void ReadMultiBlockByte(u8 BlockStartAddress,uint8_t BlockNum,
                        uint8_t ReadBlockByte[]);

chipeeprom.c源文件:

#include "include.h"
/*******************************************************************************
****函数名称:
****函数功能:任意写多个Block字节
****入口参数:
          BlockStartAddress    字节被写入的Block首地址
          FLASH_MemType        FLASH Memory操作类型
          FLASH_ProgMode       FLASH 编程模式
          Buffer               要写进flash eeprom 的字节数组
          BlockNum             要写进flash eeprom 的Block个数
****出口参数:无
****说明:每种型号的EEPROM的大小不一样,调用此函数的时候要注意将要写进的字节数组
         的大小是否超过该型号的EEPROM的地址。
         大容量的EEPROM的型号是STM8S208, STM8S207, STM8S007, STM8AF52Ax, STM8AF62Ax 
         EEPROM的地址是从0x004000到0x0047ff,共2048Byte,每个Block是128Byte,一共16个Block.
         中容量的EEPROM的型号是STM8S105, STM8S005, STM8AF626x
         EEPROM的地址是从0x004000到0x0043ff,共1024Byte,每个Block是128Byte,一共8个Block.
         小容量的EEPROM的型号是STM8S103, STM8S003, STM8S903 
         EEPROM的地址是从0x004000到0x00427f,共1024Byte,每个Block是64Byte,一共10个Block.
********************************************************************************/
void WriteMultiBlockByte(u8 BlockStartAddress,FLASH_MemType_TypeDef FLASH_MemType, 
                FLASH_ProgramMode_TypeDef FLASH_ProgMode, uint8_t *Buffer,uint8_t BlockNum)
{
  uint8_t  BlockNum_Temp;
  /* 解锁 flash data eeprom memory */
  FLASH_Unlock(FLASH_MEMTYPE_DATA);
  /* 等待 Data EEPROM area 解锁标志位置位*/
  while (FLASH_GetFlagStatus(FLASH_FLAG_DUL) == RESET) ;
  for(BlockNum_Temp=BlockStartAddress;BlockNum_Temp<BlockNum;BlockNum_Temp++)
  {
      if(BlockNum_Temp>FLASH_DATA_BLOCKS_NUMBER)
         break;
      FLASH_ProgramBlock(BlockNum_Temp, FLASH_MemType, FLASH_ProgMode,Buffer+BlockNum_Temp*FLASH_BLOCK_SIZE);
      FLASH_WaitForLastOperation(FLASH_MemType);
  }
  FLASH_Lock(FLASH_MEMTYPE_DATA);/*操作完要加锁*/
}
/*******************************************************************************
****函数名称:
****函数功能:任意读多个Block字节
****入口参数:
         BlockStartAddress    读Block首地址
         BlockNum                 读多少Block
         ReadBlockByte[]       存放读到字节的数组
****出口参数:无
********************************************************************************/
void ReadMultiBlockByte(u8 BlockStartAddress,uint8_t BlockNum,uint8_t ReadBlockByte[])
{
    uint32_t add, start_add, stop_add;
    start_add = FLASH_DATA_START_PHYSICAL_ADDRESS+(u32)((BlockNum-1)*FLASH_BLOCK_SIZE);
    stop_add = FLASH_DATA_START_PHYSICAL_ADDRESS + (u32)(BlockNum*FLASH_BLOCK_SIZE);
    for (add = start_add; add < stop_add; add++)
        ReadBlockByte[add-FLASH_DATA_START_PHYSICAL_ADDRESS]=FLASH_ReadByte(add);
}

主函数(这里只列举了关于EEPROM读写的相关程序代码)

#include "include.h"

u8 WriteBuffer[FLASH_BLOCK_SIZE];  //设置一个数组用于保存程序运行中的数据
u8 ReadBuffer[FLASH_BLOCK_SIZE];

void main(void)
{

      ......

      WriteMultiBlockByte(0,FLASH_MEMTYPE_DATA,FLASH_PROGRAMMODE_STANDARD,WriteBuffer,1);

      ......

       ReadMultiBlockByte(0,1,ReadBuffer);

}


原创粉丝点击