!!!ATTENTION:若要使LSI作为主时钟源,需要让选项字节位LSI_EN为1.
可通过修改Option Byte的配置来使能LSI时钟 (将LSI_EN位设置为LSI Clock available as CPU clock source);也可以设置相关寄存器实现主时钟源在HSI和LSI之间切换,需要注意的是在设置切换到LSI时要置位LSI_EN来使能切换,要设置前还需要解除选项字节写保护,并且还要使能OPT写操作。在设置好LSI_EN这一位后,还要恢复选项字节写保护。
void SET_LSI_EN(void)
{
if(*(unsigned char*)0x4805!=0x08)//判断LSI_EN是否为1,不是1则将其置1
{
FLASH->DUKR=0xAE;
FLASH->DUKR=0x56;//解除选项字节写保护
while(!(FLASH->IAPSR&0x08));//等待解除成功
FLASH->CR2=0x80;
FLASH->NCR2=0x7f;//使能OPT写操作
*(unsigned char*)0x4805=0x08;
*(unsigned char*)0x4806=0xf7;//置位LSI_EN
FLASH_IAPSR&=~0x08;
}
//*********************************************************************************************
//函数功能:自动切换时钟源
//入口参数: 无
//返 回:无
//备 注:先判断当前时钟源后再执行自动转换
//*********************************************************************************************
void AUTO_CLOCK_SWITCH_CONFIG(void)
{
if(CLK_GetSYSCLKSource()!=CLK_SOURCE_HSE)
{
while(CLK_ClockSwitchConfig(CLK_SWITCHMODE_AUTO,//选择自动切换模式
CLK_SOURCE_HSE,//切换时钟源为HSE
DISABLE,//关闭切换中断
CLK_CURRENTCLOCKSTATE_ENABLE)切换到时钟源后继续开启旧时钟源
==ERROR);//等待自动切换成功
}
//*********************************************************************************************
//函数功能:手动切换时钟源
//入口参数: 无
//返 回:无
//备 注:使能切换中断,当目标时钟震荡稳定后,切换条件成熟,产生中断,
在中断中使能切换控制位,主函数记得开总中断
//*********************************************************************************************
void HAND_CLOCK_SWITCH_CONFIG(void)
{
CLK_ClockSwitchConfig(CLK_SWITCHMODE_MANUAL,//选择手动切换模式
CLK_SOURCE_HSE,//切换时钟源为HSE
ENABLE,//开启切换中断
CLK_CURRENTCLOCKSTATE_ENABLE);//切换到时钟源后继续开启旧时钟源
}
//中断函数
INTERRUPT_HANDLER(CLK_IRQHandler,2)
{
CLK_ClearITPendingBit(CLK_IT_SWIF);//清除中断标志位
CLK_ClockSwitchCmd(ENABLE);//使能切换标志位,完成切换
}
//*********************************************************************************************
//函数功能:写中断的步骤
//入口参数: 无
//返 回:无
//备 注:1、设置触发方式 2、设置中断优先级 3、设置I/O口引脚配置(所有用到的引脚,包括普通I/O口和中断触发引脚)4、开总中断(此处没有设置中断优先级,默认软件优先级为3)
//*********************************************************************************************
void EXTI_CONFIG(void)
{
EXTI_SetExtIntSensitivity(EXTI_PORT_GPIOA,EXTI_SENSITIVITY_FALL_ONLY);//I/O口A仅下降沿触发
GPIO_Init(实际用到的端口设置);
rim();//开总中断
}
!!!ATTENTION:在中断函数里面关闭中断,即执行asm(“SIM”)是无效的,要关闭中断可直接关闭I/O口的中断功能,即CR2相关寄存器的值写0.(PB_CR2&=~(1<<6))
//*********************************************************************************************
//函数功能:Timer1初始化配置函数
//入口参数: 无
//返 回:无
//备 注:配置八分频,向上计数,每次t
//**********************************************************************************************
void Tim1_Init()
{
TIM1_DeInit();
TIM1_TimeBaseInit(0x0007,TIM1_COUNTERMODE_UP,100,0x00);//八分频,t=(8/2MHz)*100,100是溢出值
TIM1_ARRPreloadConfig(ENABLE);//使能自动重装
TIM1_SetCounter(0x0);//设置TMI1计数器寄存器的值(初装置值)
TIM1_ITConfig(TIM1_IT_UPDATE , ENABLE);//数据更新中断及使能
TIM1_Cmd(ENABLE);//开定时器
}
//************************************************************************************************
//函数功能:TIM1 测量占空比跟频率的初始化函数
//入口参数: 无
//返 回:无
//备 注:
//************************************************************************************************
void Tim1_INIT(void)
{
TIM1_DeInit();
TIM1_PWMIConfig(TIM1_CHANNEL_1, TIM1_ICPOLARITY_RISING,
TIM1_ICSELECTION_DIRECTTI, TIM1_ICPSC_DIV1, 0x00);
TIM1_SelectInputTrigger(TIM1_TS_TI1FP1);//选择触发信号
TIM1_SelectSlaveMode(TIM1_SLAVEMODE_RESET);//复位触发
TIM1_ClearFlag(TIM1_FLAG_CC1); //指定要清除的标志
TIM1_ClearFlag(TIM1_FLAG_CC2); //指定要清除的标志
TIM1_UpdateRequestConfig(TIM1_UPDATESOURCE_REGULAR);//设置产生中断的条件
TIM1_ITConfig(TIM1_IT_UPDATE, ENABLE);//使能更新中断
TIM1_ITConfig(TIM1_IT_CC1, ENABLE);
TIM1_ITConfig(TIM1_IT_CC2, ENABLE);
TIM1_CCxCmd(TIM1_CHANNEL_1, ENABLE); //使能输入捕获通道1
TIM1_CCxCmd(TIM1_CHANNEL_2, ENABLE); //使能输入捕获通道2
TIM1_Cmd(ENABLE);//开TIM1
}
//************************************************************************************************
//函数功能:TIM2 PWM输出波形
//入口参数: 无
//返 回:无
//备 注:输出波形频率为1KHz(16MHz/16)/(999+1)=1KHz
//************************************************************************************************
void Timer2_PWM_Output(void)//输出频率为1kHz,占空比为75%的方波
{
TIM2_DeInit();
TIM2_TimeBaseInit(TIM2_PRESCALER_16, 999);//(此处的主时钟为16MHz)预分频为16,自动装载值为999
//PWM模式1,启用输出比较,脉冲宽度为750,输出比较极性为高电平
TIM2_OC1Init(TIM2_OCMODE_PWM1, TIM2_OUTPUTSTATE_ENABLE, 750,TIM2_OCPOLARITY_HIGH);
TIM2_OC1PreloadConfig(ENABLE); //输出比较1预装载使能
TIM2_ARRPreloadConfig(ENABLE);//允许自动预装载
TIM2_Cmd(ENABLE); //开定时器2
}
//************************************************************************************************
//函数功能:SPI通信初始化配置函数
//入口参数: 无
//返 回:无
//备 注:无
//************************************************************************************************
void SPI_Config(void)
{
SPI_DeInit();//恢复SPI寄存器到默认值
/*SPI初始化: 高位在前;
波特率为主时钟的1/2;
主机模式;
空闲状态时SCK保持低电平;
数据采样从第一个时钟边沿开始;
双线单向数据模式;
禁止软件从设备管理;
CRC多项式*/
SPI_Init( SPI_FIRSTBIT_MSB,
SPI_BAUDRATEPRESCALER_2,
SPI_MODE_MASTER,
SPI_CLOCKPOLARITY_LOW,
SPI_CLOCKPHASE_1EDGE,
SPI_DATADIRECTION_2LINES_FULLDUPLEX,
SPI_NSS_SOFT,
0x00);
SPI_ITConfig(SPI_IT_TXE, ENABLE);
SPI_Cmd(ENABLE);
}
//*************************************************************************************************
//函数功能:串口初始化配置函数
//入口参数: 无
//返 回:无
//备 注:此处没有配置fmaster,默认为8分频的HSI(2MHz)
//***********************************************************************************************
void UART1_Config(void)
{
CLK_DeInit();//恢复默认设置
UART1_Init((u32)9600,//设置波特率为9600
UART1_WORDLENGTH_8D,//8位数据位
UART1_STOPBITS_2,//2位停止位
UART1_PARITY_NO,//无奇偶校验
UART1_SYNCMODE_CLOCK_DISABLE, //禁用同步模式
UART1_MODE_TXRX_ENABLE//发送接收使能
);
UART1_Cmd(DISABLE);//启用UART1
}
//*****************************************************************************************************
//函数功能:打印函数重定向
//入口参数: putchar的参数是待发送的字节c
//返 回:一个字符c
//备 注:重定向后可直接使用PRINTF,GETCHAR等函数进行通信
!!!使用前一定要在main()中进行初始化,int getchar(void);int putchar(int c);
//******************************************************************************************************
int getchar(void)
{
int c=0;
/*等待读缓冲区非空标志置一(RxNE==1)*/
while(UART1_GetFlagStatus(UART1_FLAG_RXNE)==RESET);
c=UART1_ReceiveData8();
return(c);
}
int putchar(int c)
{
/*向UART1写入一个字节*/
UART1_SendData8(c);
/*等待发送缓冲区空标志置一(TxE==1)*/
while(UART1_GetFlagStatus(UART1_FLAG_TXE)==RESET);
return(c);
}
//*******************************************************************************************************
//函数功能:I2C初始化
//入口参数: 无
//返 回:无
//备 注:
//*******************************************************************************************************
void I2C_Config(void)
{
/*1、设置时钟*/
CLK_PeripheralClockConfig(CLK_PERIPHERAL_I2C,ENABLE);//启用I2C外围时钟
/*2、初始化I2C*/
I2C_Init(100000, //通信速度(Hz)范围在100k~400k之间
0xA0, //本机地址
I2C_DUTYCYCLE_2, //快速模式下时钟信号的占空比(1/2或9/16,此处是1/2)
I2C_ACK_CURR, //应答方式(此处是本次数据应答)
I2C_ADDMODE_7BIT, //7位从机地址模式
16 //I2C输入时钟频率(MHz)
);
/*3、开启中断*/
I2C_ITConfig((I2C_IT_TypeDef)(I2C_IT_EVT|I2C_IT_BUF),ENABLE);//开启I2C缓冲和事件中断
}
//*********************************************************************************************
//函数功能:独立看门狗初始化
//入口参数: 无
//返 回:无
//备 注:250ms后喂狗,LSI控制
//********************************************************************************************
static void IWDG_Config(void)
{
//需要硬件启动LSI时钟
AccessCmd(IWDG_WriteAccess_Enable);//使能IWDG_PR和IWDG_RLR写操作
IWDG_SetPrescaler(IWDG_Prescaler_128);//对LSI时钟128分频
/*250ms后喂狗需要设置的数值
Counter Reload Value = 250ms/IWDG counter clock period
= 250ms /(1/ (LSI/128))
= 0.25s /(1/(LsiFreq/128))
=lsiFreq/(128 *4)
=lsiFreq/512 */
IWDG_SetReload((uint8_t)(LsiFreq/512));//设置重载值,250ms后重载
IWDG_ReloadCounter();//重载计数器
IWDG_Enable();//启动独立看门狗
}
//********************************************************************************************************
//函数功能:窗口看门狗初始化
//入口参数: 无
//返 回:无
//备 注:0到43.008ms内喂狗失败,43.008~2519ms喂狗成功,主时钟HSI八分频(2MHz)控制
//*********************************************************************************************************
static void WWDG_Config(void)
{
/*
WWDG configuration: WWDG is clocked by SYSCLK = 2MHz */
CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV8);//对HSI进行八分频
/*
WWDG timeout is equal to 251,9 ms */
/*
Watchdog Window = (COUNTER_INIT - 63) * 1 step
= 41 * (12288 / 2Mhz)
= 251,9 ms
*/
/*
Non Allowed Window = (COUNTER_INIT - WINDOW_VALUE) * 1 step
= (104 - 97) * 1 step
= 7 * 1 step
= 7 * (12288 / 2Mhz)
= 43.008 ms
*/
/*
在0~43.008ms之间喂狗,则喂狗失败;在43.008ms到2519ms之间喂狗则喂狗成功 */
WWDG_Init(COUNTER_INIT, WINDOW_VALUE);//COUNTER_INIT=104,WINDOW_VALUE=97
}
//********************************************************************************************************************
//函数功能:喂(窗口看门)狗
//入口参数: 无
//返 回:无
//备 注:0到43.008ms内喂狗失败,43.008~2519ms喂狗成功,fcpu=HSI八分频(2MHz)控制
//********************************************************************************************************************
void Refresh_WWDG_Window(void)
{
u8 CounterValue;//计数器中的值
/*WINDOW_INIT 窗口值 , COUNTER_INIT 计数器初始值*/
CounterValue = (u8)(WWDG_GetCounter() & 0x7F); //读取WWDR->CR中的7位计数器中的值
if(CounterValue < WINDOW_INIT)
{
WWDG_SetCounter( COUNTER_INIT); //进行设置WWDG的计数器值,喂狗
}
}
/*提前喂狗
if(CounterValue>WINDOW_INIT)
{
WWDG_SetCounter(COUNTER_INIT);//进行设置WWDG的计数器值,喂狗,提前喂狗,喂狗会失败
}
*/