STM8时钟切换(支持HSI/HSE切换)+EEPROM操作支持(就像定义变量一样)+中断优先级配置(3级优先级设置)+选项字编程

2019-07-19 20:45发布

还是参考战舰板的sys.c和sys.h,实现了STM8的sys.c和sys.h,本代码实现功能:
1,支持STM8的时钟设置,包括HSI/HSE,以及分频等.
2,支持IAR自带的__eeprom关键字,直接像使用内存一样使用eeprom.
比如:
__eeprom __no_init u8 test_eeprom; //定义一个eeprom测试数据
就定义了一个数据 test_eeprom,存放在eeprom里面,操作 test_eeprom这个eeprom数据就和操作内存一样. 3,支持中断优先级设置.三个等级.
4,支持外部中断触发设置.
5,支持选项字编程,这个时钟设置的时候需要用到,所以顺带放在sys.c里面了.


以下为代码,未经过完整的测试,在STM8S208上面实现的,其他型号暂时还没测试,如有问题,请大家反馈.
sys.h代码如下:
#ifndef  __SYS_H #define  __SYS_H #include "stm8s.h" //stm8系列共用头文件. #include "stdbool.h"     //BOOL 类型头文件  #include "intrinsics.h" //总中断头文件 ////////////////////////////////////////////////////////////////////////////////   //本程序只供学习使用,未经作者许可,不得用于其它任何用途 //ALIENTEK //系统相关代码    //正点原子@ALIENTEK //技术论坛:www.openedv.com //修改日期:2013/6/27 //版本:V1.1 //版权所有,盗版必究。 //Copyright(C) 广州市星翼电子科技有限公司 2009-2019 //All rights reserved //****************************************************************************** //V1.0 20130625 //支持选项字编程 //支持IAR EEPROM变量定义操作 //支持系统时钟初始化设置,包括HSE/HSI设置以及分频设置  //V1.1 20130627 //增加中断管理函数ITC_Set和EXTI_Config  //////////////////////////////////////////////////////////////////////////////// //用户配置区
//如果使用了外部晶振,且频率大于16Mhz,请定义这里为1,否则定义为0即可 #define STM8_HSE_B16M 0X01

//////////////////////////////////////////////////////////////////////////////// //常用数据类型定义 #define u8  uint8_t #define u16 uint16_t #define u32 uint32_t //STM8S中断总开关,在使用中断的时候,记得先开启总开关 #define INT_ENABLE() __enable_interrupt() //开启所有中断 #define INT_DISABLE()   __disable_interrupt() //关闭所有中断 //////////////////////////////////////////////////////////////////////////////// //FLASH操作部分宏定义 #define FLASH_UNLOCK_KEY1 0x56  //第一个密钥 #define FLASH_UNLOCK_KEY2 0xAE  //第二个密钥
#define OPT_ROP_ADDR (u16)0X4800 #define OPT_UBC_ADDR (u16)0X4801 #define OPT_AFR_ADDR (u16)0X4803 #define OPT_WDG_ADDR (u16)0X4805 #define OPT_CLK_ADDR (u16)0X4807 #define OPT_HSESTARTUP_ADDR (u16)0X4809 #define OPT_FLASHWAIT_ADDR (u16)0X480D #define OPT_BOOTLOADER_ADDR (u16)0X487E //////////////////////////////////////////////////////////////////////////////// //中断向量号集 #define TLI_VECTOR 0 #define AWU_VECTOR 1 #define CLK_VECTOR 2 #define EXTI_PA_VECTOR 3 #define EXTI_PB_VECTOR 4 #define EXTI_PC_VECTOR 5 #define EXTI_PD_VECTOR 6 #define EXTI_PE_VECTOR 7 #define CAN_RX_VECTOR 8 #define CAN_TX_VECTOR 9 #define SPI_VECTOR 10 #define TIM1_UPD_OVF_VECTOR 11 #define TIM1_CAP_COM_VECTOR 12 #define TIM2_UPD_OVF_VECTOR 13 #define TIM2_CAP_COM_VECTOR 14 #define TIM3_UPD_OVF_VECTOR 15 #define TIM3_CAP_COM_VECTOR 16 #define UART1_TX_VECTOR 17 #define UART1_RX_VECTOR 18  #define I2C_VECTOR 19  #define UART23_TX_VECTOR 20  #define UART23_RX_VECTOR 21  #define ADC_VECTOR 22  #define TIM4_UPD_OVF_VECTOR 23  #define FLASH_VECTOR 24  //EXTI_Config函数,GPIO定义(包括TLI) #define GPIO_A 0 #define GPIO_B 1 #define GPIO_C 2 #define GPIO_D 3 #define GPIO_E 4  #define GPIO_TLI 5 //TLI中断 //EXTI_Config函数,触发方式定义(TLI仅支持上升沿/下降沿触发) #define FLTIR   0   //下降沿和低电平触发 #define RTIR   1 //仅上升沿触发 #define FTIR   2   //仅下降沿触发 #define RFTIR 3   //上升沿和下降沿触发 ////////////////////////////////////////////////////////////////////////////////
void STMFLASH_Unlock(u8 type); void STMFLASH_Lock(u8 type); u8 STMFLASH_WaitForLastOperation(u8 type); void STMFLASH_EraseOptionByte(u16 addr); void STMFLASH_ProgramOptionByte(u16 addr,u8 data); u16 STMFLASH_ReadOptionByte(u16 addr); void ITC_Set(u8 vector,u8 priority); void EXTI_Config(u8 GPIOx,u8 TRIM); u8 System_Clk_AutoSwitch(u8 newsrc); void System_Clk_DivSet(u8 div); void stm8_clock_init(u8 clksrc,u8 div);
#endif





sys.c代码如下:
#include "sys.h"  ////////////////////////////////////////////////////////////////////////////////   //本程序只供学习使用,未经作者许可,不得用于其它任何用途 //ALIENTEK //系统相关代码    //正点原子@ALIENTEK //技术论坛:www.openedv.com //修改日期:2013/6/27 //版本:V1.1 //版权所有,盗版必究。 //Copyright(C) 广州市星翼电子科技有限公司 2009-2019 //All rights reserved //****************************************************************************** //V1.0 20130625 //支持选项字编程 //支持IAR EEPROM变量定义操作 //支持系统时钟初始化设置,包括HSE/HSI设置以及分频设置  //V1.1 20130627 //增加中断管理函数ITC_Set和EXTI_Config  ////////////////////////////////////////////////////////////////////////////////  
//解锁STM8S的FLASH //0,程序存储区(FLASH)解锁 //1,数据存储区(EEPROM)解锁 void STMFLASH_Unlock(u8 type) {     if(type==0) //程序存储区(FLASH)解锁     {         FLASH->UKR=FLASH_UNLOCK_KEY1;         FLASH->UKR=FLASH_UNLOCK_KEY2;     }      else //数据区(EEPROM)解锁     {         FLASH->DUKR=FLASH_UNLOCK_KEY2; //注意,这里和数据手册写的有出入!!!          FLASH->DUKR=FLASH_UNLOCK_KEY1;     }  while(!(FLASH->IAPSR&(1<<3))); //等待解锁成功 } //STM8S的FLASH上锁 //0,程序存储区(FLASH)上锁 //1,数据存储区(EEPROM)上锁 void STMFLASH_Lock(u8 type) { if(type==0)FLASH->IAPSR&=~(1<<1); //主程序存储区(FLASH)上锁 else FLASH->IAPSR&=~(1<<3); //数据存储区(EEPROM)上锁 }  //等待FLASH操作完成 //type: //0,等待程序存储区(FLASH)操作 //1,等待数据存储区(EEPROM)操作 //返回值:0,成功;1,失败. u8 STMFLASH_WaitForLastOperation(u8 type) {     u8  status=0X00;     u32 timeout=0XFFFFF;  #if defined(STM8S208)||defined(STM8S207)||defined(STM8S007)||defined(STM8S105)||     defined(STM8S005)||defined(STM8AF52Ax)||defined(STM8AF62Ax)||defined(STM8AF626x)       if(type==0)//等待FLASH操作结束     {         while((status==0x00)&&timeout)         {             status=FLASH->IAPSR&(1<<2|1<<0);             timeout--;         }     }else //等待EEPROM操作结束     {         while((status==0x00)&&timeout)         {             status=FLASH->IAPSR&(1<<6|1<<0);             timeout--;                    }     } #else//STM8S103, STM8S903 while((status&&timeout) { status=FLASH->IAPSR&(1<<2|1<<0); timeout--;     } #endif      if(timeout==0)return 1; return 0;  } //擦除选项字 //addr:选项字地址 void STMFLASH_EraseOptionByte(u16 addr) {      FLASH->CR2|=1<<7; //选项字写使能     FLASH->NCR2&=~(1<<7); //互补选项字写使能  if(addr==0x4800) //写ROP,没有互补选项字     {         *((NEAR u8*)addr)=0X00; //清零     }else      {         *((NEAR u8*)addr)=0X00; //清零        *((NEAR u8*)((u16)(addr+1)))=0XFF;//互补设置     }     STMFLASH_WaitForLastOperation(0);//等待写完成      FLASH->CR2&=~(1<<7); //选项字写禁止     FLASH->NCR2|=1<<7; //互补选项字写禁止  } //编程选项字 //addr:选项字地址  //data:要写入的值 void STMFLASH_ProgramOptionByte(u16 addr,u8 data) {      FLASH->CR2|=1<<7; //选项字写使能     FLASH->NCR2&=~(1<<7); //互补选项字写使能  if(addr==0x4800) //写ROP,没有互补选项字     {         *((NEAR u8*)addr)=data; //写选项字     }else      {         *((NEAR u8*)addr)=data; //写选项字        *((NEAR u8*)((u16)(addr+1)))=(u8)(~data);//写互补字节     }      STMFLASH_WaitForLastOperation(0); //等待写完成     FLASH->CR2&=~(1<<7); //选项字写禁止     FLASH->NCR2|=1<<7; //互补选项字写禁止  } //读取OPT字节 //addr:OPT字节地址 //返回值:读取到的内容,如果>0XFF,则读数有问题.如果<=0XFF,正确的OPT读数 u16 STMFLASH_ReadOptionByte(u16 addr) {     u8 value_optbyte,value_optbyte_complement=0;     u16 res_value=0;       value_optbyte=*((NEAR u8*)addr); //读取OPT字节     value_optbyte_complement=*(((NEAR u8*)addr)+1); //读取互补OPT字节     res_value=value_optbyte; //返回值为opt值 if(value_optbyte!=(u8)(~value_optbyte_complement))res_value=0X5555;//OPT有误   if(addr==0X4800)res_value=value_optbyte; //ROP不存在互补opt,直接返回opt值     return res_value; } //以下三个函数,以支持IAR独有的__eeprom关键字操作 //EEPROM完成操作等待 void __eeprom_wait_for_last_operation(void) { STMFLASH_WaitForLastOperation(1); //等待操作结束 } //EEPROM,在指定位置写入一个字节数据 //addr:地址 //data:要写入的数据 void __eeprom_program_byte(unsigned short addr,unsigned char data) { __eeprom_wait_for_last_operation();     STMFLASH_Unlock(1);  *(PointerAttr u8*)(u16)addr=data; __eeprom_wait_for_last_operation();  STMFLASH_Lock(1);    }     //EEPROM,在指定位置写入一个long型数据(4字节) //addr:地址 //data:要写入的long型数据 void __eeprom_program_long(unsigned short addr,unsigned long data) { __eeprom_wait_for_last_operation();     STMFLASH_Unlock(1);  *(PointerAttr u8*)(u16)addr=(u8)(data>>24);   __eeprom_wait_for_last_operation();  *(PointerAttr u8*)(u16)(addr+1)=(u8)(data>>16);   __eeprom_wait_for_last_operation();  *(PointerAttr u8*)(u16)(addr+2)=(u8)(data>>8);   __eeprom_wait_for_last_operation();  *(PointerAttr u8*)(u16)(addr+3)=(u8)(data&0XFF);   __eeprom_wait_for_last_operation();   STMFLASH_Lock(1);  }  //软件中断优先级设置函数 //vector:中断向量号(0~24) //prio:优先级(1~3),禁止设置为0 //STM8的优先级分为软件优先级和硬件优先级,软件优先级优先于硬件优先级. //硬件优先级由向量号确定,向量号越小,优先级越高. //软件优先级可以通过本函数设置. //STM8软件优先级设置可以分为4个等级(0~3),实际上可设置的就三个等级:1~3 //优先级顺序:0<1<2<3,3的优先级最高,高优先级的中断可以打断低优先级的中断 //多个中断同时发生:在软件优先级相同的情况下,由硬件优先级决定谁先响应. void ITC_Set(u8 vector,u8 priority) {  if(priority==0)return; //不能设置为优先级0 if(priority==2)priority=0; //优先级2:00B if(vector<4) { ITC->ISPR1&=~(3<<vector*2); //清除原来的设置 ITC->ISPR1|=priority<<vector*2; //设置优先级 }else if(vector<8) { ITC->ISPR2&=~(3<<(vector-4)*2); //清除原来的设置 ITC->ISPR2|=priority<<(vector-4)*2; //设置优先级 }else if(vector<12) { ITC->ISPR3&=~(3<<(vector-8)*2); //清除原来的设置 ITC->ISPR3|=priority<<(vector-8)*2; //设置优先级 }else if(vector<16) { ITC->ISPR4&=~(3<<(vector-12)*2); //清除原来的设置 ITC->ISPR4|=priority<<(vector-12)*2;//设置优先级 }else if(vector<20) { ITC->ISPR5&=~(3<<(vector-16)*2); //清除原来的设置 ITC->ISPR5|=priority<<(vector-16)*2;//设置优先级 }else if(vector<24) { ITC->ISPR6&=~(3<<(vector-20)*2); //清除原来的设置 ITC->ISPR6|=priority<<(vector-20)*2;//设置优先级 }else if(vector<28) { ITC->ISPR7&=~(3<<(vector-24)*2); //清除原来的设置 ITC->ISPR7|=priority<<(vector-24)*2;//设置优先级 }else if(vector<32) { ITC->ISPR8&=~(3<<(vector-28)*2); //清除原来的设置 ITC->ISPR8|=priority<<(vector-28)*2;//设置优先级 } } //外部中断配置函数 //GPIO:0~5(对应GPIO_A~GPIO_E和TLI) //TRIM:0~3(即00B~11B) //00,下降沿和低电平触发 //01,仅上升沿触发 //10,仅下降沿触发 //11,上升沿和下降沿触发 void EXTI_Config(u8 GPIOx,u8 TRIM) { TRIM&=0X03; //取低2位有效 if(GPIOx<4) //GPIOA~D { EXTI->CR1&=~(3<<GPIOx*2); //清除原来的设置 EXTI->CR1|=TRIM<<GPIOx*2; //设置触发方式 }else if(GPIOx==GPIO_E) //GPIOE { EXTI->CR2&=~(3<<0); //清除原来的设置 EXTI->CR2|=TRIM; //设置触发方式 }else if(GPIOx==GPIO_TLI) //TLI触发方式设置 { TRIM&=0X01; //仅最低位有效. EXTI->CR2&=~(1<<2); //清除原来的设置 EXTI->CR2|=TRIM<<2; //设置TLI触发方式 } } //自动切换新时钟源(仅HSI/HSE) //newsrc:0,HSI //       1,HSE //返回值:0,修改成功;1,修改失败. u8 System_Clk_AutoSwitch(u8 newsrc) { u16 timeout=0xffff; u8 oldsrc=CLK->CMSR; //老的时钟源 CLK->SWCR|=1<<1; //使能时钟切换功能 CLK->SWCR&=~(1<<2); //关闭切换中断 if(newsrc==0)CLK->SWR=0XE1; //HSI else CLK->SWR=0XB4; while((CLK->SWCR&(1<<0))&timeout)timeout--; //等待切换完成 if(oldsrc==0XE1&&newsrc==0XB4)CLK->ICKR&=~(1<<0); //关闭HSI else if(oldsrc==0XB4&&newsrc==0XE1)CLK->ECKR&=~(1<<0); //关闭HSE if(timeout)return 0; else return 1; } //设置分配系数 //div:0~7,代表2的0~7次幂分频 void System_Clk_DivSet(u8 div) {  CLK->CKDIVR=0; //清除原来的设置 CLK->CKDIVR=div&0X07; //设置DIV  }   
//STM8时钟配置 //clksrc:0,HSI(16M)做为时钟源;1,HSE(最大24M)作为时钟源 //div:分配系数,0~7,代表2的0~7次幂分频 void stm8_clock_init(u8 clksrc,u8 div) { u16 fwait=0; fwait=STMFLASH_ReadOptionByte(OPT_FLASHWAIT_ADDR); //读取wait值 if(clksrc==1&&STM8_HSE_B16M&&div==0) //HSE做时钟,且外部晶振大于16M,且未分频 { if(fwait!=0X01)//没有设置wait值,则需要设置 STMFLASH_Unlock(1); //先解锁   STMFLASH_ProgramOptionByte(OPT_FLASHWAIT_ADDR,1); //大于16Mhz,写入1个flash等待周期 STMFLASH_ProgramOptionByte(OPT_HSESTARTUP_ADDR,0XB4); //稳定周期设置为128个时钟周期  STMFLASH_Lock(1); //上锁  } }else //否则,不需要flash等待周期 {   if(fwait==0X01)//设置了wait值,则需要去掉 { STMFLASH_Unlock(1);  STMFLASH_EraseOptionByte(OPT_FLASHWAIT_ADDR); //HSI,不需要FLASH等待周期,提高速度 STMFLASH_EraseOptionByte(OPT_HSESTARTUP_ADDR); //不需要稳定周期 STMFLASH_Lock(1);  }   } System_Clk_DivSet(div); //设置分频 while(System_Clk_AutoSwitch(clksrc)); //切换时钟 }
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。