文章目录:
一:低功耗模式
1.睡眠模式测试程序
NVIC.h
NVIC.c
key.h
key.c
main.c
2.停机模式测试程序
main.c
3.待机模式测试程序
main.c
二:看门狗
1.独立看门狗测试程序
iwdg.h
iwdg.c
main.c
2.窗口看门狗测试程序
wwdg.h
wwdg.c
main.c
三:TIM定时器
tim.h
tim.c
main.c
四:CRC循环冗余校验计算单元与芯片ID
1.CRC功能测试程序
main.c
2.芯片ID读取程序
main.c
五:还需要补充的知识
这些是单片机的辅助功能
单片机内部功率是各功能部分功率的总和 低功耗模式是通过关掉部分内部功能达到省电 STM32F103单片机共有3种低功耗模式 不同模式会对系统正常工作有一定影响,需要按实际情况选择 低功耗模式只针对单片机内部功能,外接电路产生的功耗不在其内 单片机最小系统电路功耗,不精确测量值 √正常模式:10mA √睡眠模式:2mA √停机模式:20uA √待机模式:2uA 睡眠模式 在ARM内核无事可做的时候,可以进入睡眠模式 例如:电脑的CPU空闲状态就是单片机睡眠模式 睡眠模式的应用不多,因只关闭ARM内核,节能有限,很少在非操作系统程序(裸机)中使用 在嵌入式操作系统中,会采用睡眠模式 优点:对系统影响最小 缺点:节能效果最差 停机模式 因SRAM内容不消失,程序不复位,可在唤醒后继续运行 节能效果与待机模式近似,却有着更多优势 主要用于电池供电的设备上,提高电池寿命 在电池供电的产品中必须使用,在外部供电的产品中没必要使用 优点:节能效果好,程序不会复位 缺点:恢复时间较长 待机模式 由于SRAM内容消失,唤醒后程序必须复位,从头开始运行 因为待机和停机之间的功耗差别是uA级的,几乎没有差别,所以开发者大多使用停机模式,待机模式极少使用 在一些偶尔需要工作的场合,且工作量不大、不复杂的情况下,待机模式可以保证最低的功耗 比如应用在室外温度测量产品上,每1小时测量一次。可用RTC闹钟唤醒,测量完再待机。、 优点:最节能 缺点:程序会复位,只有少数条件可唤醒
NVIC.h
#ifndef __NVIC_H #define __NVIC_H #include "sys.h" extern u8 INT_MARK;//中断标志位 void KEY_INT_INIT (void); #endif
NVIC.c
#include "NVIC.h" u8 INT_MARK;//中断标志位 void KEY_INT_INIT (void){ //按键中断初始化 NVIC_InitTypeDef NVIC_InitStruct; //定义结构体变量 EXTI_InitTypeDef EXTI_InitStruct; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); //启动GPIO时钟 (需要与复用时钟一同启动) RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO , ENABLE);//配置端口中断需要启用复用时钟 GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0); //定义 GPIO 中断 EXTI_InitStruct.EXTI_Line=EXTI_Line0; //定义中断线 EXTI_InitStruct.EXTI_LineCmd=ENABLE; //中断使能 EXTI_InitStruct.EXTI_Mode=EXTI_Mode_Interrupt; //中断模式为 中断 EXTI_InitStruct.EXTI_Trigger=EXTI_Trigger_Falling; //下降沿触发 EXTI_Init(& EXTI_InitStruct); NVIC_InitStruct.NVIC_IRQChannel=EXTI0_IRQn; //中断线 NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE; //使能中断 NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=2; //抢占优先级 2 NVIC_InitStruct.NVIC_IRQChannelSubPriority=2; //子优先级 2 NVIC_Init(& NVIC_InitStruct); } void EXTI0_IRQHandler(void){ if(EXTI_GetITStatus(EXTI_Line0)!=RESET){//判断某个线上的中断是否发生 INT_MARK=1;//标志位置1,表示有按键中断 EXTI_ClearITPendingBit(EXTI_Line0); //清除 LINE 上的中断标志位 } }
key.h
#ifndef __KEY_H #define __KEY_H #include "sys.h" //#define KEY1 PAin(0)// PA0 //#define KEY2 PAin(1)// PA1 #define KEYPORT GPIOA //定义IO接口组 #define KEY1 GPIO_Pin_0 //定义IO接口 #define KEY2 GPIO_Pin_1 //定义IO接口 void KEY_Init(void);//初始化 #endif
key.c
#include "key.h" void KEY_Init(void){ //微动开关的接口初始化 GPIO_InitTypeDef GPIO_InitStructure; //定义GPIO的初始化枚举结构 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); GPIO_InitStructure.GPIO_Pin = KEY1 | KEY2; //选择端口号(0~15或all) GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //选择IO接口工作方式 //上拉电阻 // GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置IO接口速度(2/10/50MHz) GPIO_Init(KEYPORT,&GPIO_InitStructure); }
main.c
#include "stm32f10x.h" //STM32头文件 #include "sys.h" #include "delay.h" #include "relay.h" #include "oled0561.h" #include "led.h" #include "key.h" #include "NVIC.h" //中断向量控制器 int main (void){//主程序 delay_ms(500); //上电时等待其他器件就绪 RCC_Configuration(); //系统时钟初始化 RELAY_Init();//继电器初始化 LED_Init();//LED KEY_Init();//KEY I2C_Configuration();//I2C初始化 OLED0561_Init(); //OLED初始化 OLED_DISPLAY_8x16_BUFFER(0," SLEEP TEST "); //显示字符串 INT_MARK=0;//标志位清0 NVIC_Configuration();//设置中断优先级 KEY_INT_INIT();//按键中断初始化(PA0是按键中断输入) NVIC_SystemLPConfig(NVIC_LP_SEVONPEND,DISABLE); //SEVONPEND: 0:只有使能的中断或事件才能唤醒内核。1:任何中断和事件都可以唤醒内核。(0=DISABLE,1=ENABLE) NVIC_SystemLPConfig(NVIC_LP_SLEEPDEEP,DISABLE); //SLEEPDEEP: 0:低功耗模式为睡眠模式。1:进入低功耗时为深度睡眠模式。 NVIC_SystemLPConfig(NVIC_LP_SLEEPONEXIT,DISABLE); //SLEEPONEXIT: 0: 被唤醒进入线程模式后不再进入睡眠模式。1:被唤醒后执行完相应的中断处理函数后进入睡眠模式。 while(1){ GPIO_WriteBit(LEDPORT,LED1,(BitAction)(1)); //LED控制 OLED_DISPLAY_8x16_BUFFER(4," CPU SLEEP! "); //显示字符串 delay_ms(500); // __WFI(); //进入睡眠模式,等待中断唤醒 // __WFE(); //进入睡眠模式,等待事件唤醒 GPIO_WriteBit(LEDPORT,LED1,(BitAction)(0)); //LED控制 OLED_DISPLAY_8x16_BUFFER(4," CPU WAKE UP! "); //显示字符串 delay_ms(500); // } }
main.c
#include "stm32f10x.h" //STM32头文件 #include "sys.h" #include "delay.h" #include "relay.h" #include "oled0561.h" #include "led.h" #include "key.h" #include "NVIC.h" int main (void){//主程序 delay_ms(500); //上电时等待其他器件就绪 RCC_Configuration(); //系统时钟初始化 RELAY_Init();//继电器初始化 LED_Init();//LED KEY_Init();//KEY I2C_Configuration();//I2C初始化 OLED0561_Init(); //OLED初始化 OLED_DISPLAY_8x16_BUFFER(0," STOP TEST "); //显示字符串 INT_MARK=0;//标志位清0 NVIC_Configuration();//设置中断优先级 KEY_INT_INIT();//按键中断初始化(PA0是按键中断输入) RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE); //使能电源PWR时钟 while(1){ GPIO_WriteBit(LEDPORT,LED1,(BitAction)(1)); //LED控制 OLED_DISPLAY_8x16_BUFFER(4," CPU STOP! "); //显示字符串 delay_ms(500); // PWR_EnterSTOPMode(PWR_Regulator_LowPower,PWR_STOPEntry_WFI);//进入停机模式 RCC_Configuration(); //系统时钟初始化(停机唤醒后会改用HSI时钟,需要重新对时钟初始化) GPIO_WriteBit(LEDPORT,LED1,(BitAction)(0)); //LED控制 OLED_DISPLAY_8x16_BUFFER(4," CPU WAKE UP! "); //显示字符串 delay_ms(500); // } }
对开发板跳线进行设置
触摸按键将最上方的PA0跳线断开
main.c
#include "stm32f10x.h" //STM32头文件 #include "sys.h" #include "delay.h" #include "relay.h" #include "oled0561.h" #include "led.h" int main (void){//主程序 delay_ms(500); //上电时等待其他器件就绪 RCC_Configuration(); //系统时钟初始化 RELAY_Init();//继电器初始化 LED_Init();//LED I2C_Configuration();//I2C初始化 OLED0561_Init(); //OLED初始化 OLED_DISPLAY_8x16_BUFFER(0," STANDBY TEST "); //显示字符串 RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE); //使能电源PWR时钟 PWR_WakeUpPinCmd(ENABLE);//WKUP唤醒功能开启(待机时WKUP脚PA0为模拟输入) GPIO_WriteBit(LEDPORT,LED1,(BitAction)(0)); //LED控制 OLED_DISPLAY_8x16_BUFFER(4," CPU RESET! "); //显示字符串 delay_ms(500); // GPIO_WriteBit(LEDPORT,LED1,(BitAction)(1)); //LED控制 OLED_DISPLAY_8x16_BUFFER(4," STANDBY! "); //显示字符串 delay_ms(500); // PWR_EnterSTANDBYMode();//进入待机模式 //因为待机唤醒后程序从头运行,所以不需要加while(1)的主循环体。 }
是单片机系统功能的一个辅助功能:帮助单片机自我检查、 监控单片机程序是否正常工作
看门狗定时器(WDT,Watch Dog Timer)是单片机的一个组成部分 它实际上是一个计数器,一般给看门狗计数值,程序开始运行后看门狗开始倒计数 如果程序运行正常,过一段时间CPU应发出指令让看门狗复位,重新开始倒计数 如果看门狗减到0就认为程序没有正常工作,强制整个系统复位 看门狗是一个计数器 启动后开始倒计时 每过一段时间CPU要重新写入计数值(喂狗) CPU能重写计数值,表示程序运行正常 如果程序运行出错或死机,则不能重写计数值 当计数值减到O时,看门狗会让整个单片机复位 看门狗的作用 看门狗的主要目的是监控单片机程序 如果程序不断喂狗,就证明单片机工作正常 如果程序没有喂狗,就说明单片机出了问题 看门狗不能检查问题的原因,只能通过复位单片机,让程序重新开始运行 类型:独立看门狗、窗口看门狗
独立看门狗可在计数到O前随时喂狗 用于监控程序是否正常运行
窗口看门狗必须在规定的时间范围内喂狗 作用是监控单片机运行时效是否精确
新建文件夹
Basic文件夹——>iwdg文件夹——>iwdg.c iwdg.h
iwdg.h
#ifndef __IWDG_H #define __IWDG_H #include "sys.h" //看门狗定时时间计算公式:Tout=(预分频值*重装载值)/40 (单位:ms) //当前pre为64,rlr为625,计算得到Tout时间为1秒(大概值)。 #define pre IWDG_Prescaler_64 //分频值范围:4,8,16,32,64,128,256 #define rlr 625 //重装载值范围:0~0xFFF(4095) void IWDG_Init(void); void IWDG_Feed(void); #endif
iwdg.c
#include "iwdg.h" void IWDG_Init(void){ //初始化独立看门狗 IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable); //使能对寄存器IWDG_PR和IWDG_RLR的写操作 IWDG_SetPrescaler(pre); //设置IWDG预分频值 IWDG_SetReload(rlr); //设置IWDG重装载值 IWDG_ReloadCounter(); //按照IWDG重装载寄存器的值重装载IWDG计数器 IWDG_Enable(); //使能IWDG } void IWDG_Feed(void){ //喂狗程序 IWDG_ReloadCounter();//固件库的喂狗函数 }
main.c
#include "stm32f10x.h" //STM32头文件 #include "sys.h" #include "delay.h" #include "relay.h" #include "oled0561.h" #include "led.h" #include "key.h" #include "iwdg.h" int main (void){//主程序 delay_ms(500); //上电时等待其他器件就绪 RCC_Configuration(); //系统时钟初始化 RELAY_Init();//继电器初始化 LED_Init();//LED KEY_Init();//KEY I2C_Configuration();//I2C初始化 OLED0561_Init(); //OLED初始化---------------" OLED_DISPLAY_8x16_BUFFER(0," IWDG TEST "); //显示字符串 OLED_DISPLAY_8x16_BUFFER(4," RESET! "); //显示字符串 delay_ms(800); // OLED_DISPLAY_8x16_BUFFER(4," "); //显示字符串 IWDG_Init(); //初始化并启动独立看门狗 while(1){ IWDG_Feed(); //喂狗 if(!GPIO_ReadInputDataBit(KEYPORT,KEY1)){ delay_s(2); //延时2秒,使程序不能喂狗而导致复制 } } }
新建文件夹
Basic文件夹——>wwdg文件夹——>wwdg.c wwdg.h
wwdg.h
#ifndef __WWDG_H #define __WWDG_H #include "sys.h" //窗口看门狗定时时间计算公式: //上窗口超时时间(单位us) = 4096*预分频值*(计数器初始值-窗口值)/APB1时钟频率(单位MHz) //下窗口超时时间(单位us) = 4096*预分频值*(计数器初始值-0x40)/APB1时钟频率(单位MHz) #define WWDG_CNT 0x7F //计数器初始值,范围:0x40~0x7F #define wr 0x50 //窗口值(上窗口边界),范围:0x40~0x7F #define fprer WWDG_Prescaler_8 //预分频值,取值:1,2,4,8 //如上三个值是:0x7f,0x50,8时,上窗口48MS,下窗口64MS。 void WWDG_Init(void); void WWDG_NVIC_Init(void); void WWDG_Feed(void); #endif
wwdg.c
#include "wwdg.h" void WWDG_Init(void){ //初始化窗口看门狗 RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE); // WWDG 时钟使能 WWDG_SetPrescaler(fprer); //设置 IWDG 预分频值 WWDG_SetWindowValue(wr); //设置窗口值 WWDG_Enable(WWDG_CNT); //使能看门狗,设置 counter WWDG_ClearFlag(); //清除提前唤醒中断标志位 WWDG_NVIC_Init(); //初始化窗口看门狗 NVIC WWDG_EnableIT(); //开启窗口看门狗中断 } void WWDG_NVIC_Init(void){ //窗口看门狗中断服务程序(被WWDG_Init调用) NVIC_InitTypeDef NVIC_InitStructure; NVIC_InitStructure.NVIC_IRQChannel = WWDG_IRQn; //WWDG 中断 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //抢占 2 子优先级 3 组 2 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //抢占 2,子优先级 3,组 2 NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE; NVIC_Init(&NVIC_InitStructure); //NVIC 初始化 } void WWDG_Feed(void){ //窗口喂狗程序 WWDG_SetCounter(WWDG_CNT); //固件库的喂狗函数 } void WWDG_IRQHandler(void){ //窗口看门狗中断处理程序 WWDG_ClearFlag(); //清除提前唤醒中断标志位 //此处加入在复位前需要处理的工作或保存数据 }
main.c
#include "stm32f10x.h" //STM32头文件 #include "sys.h" #include "delay.h" #include "relay.h" #include "oled0561.h" #include "led.h" #include "key.h" #include "wwdg.h" int main (void){//主程序 delay_ms(500); //上电时等待其他器件就绪 RCC_Configuration(); //系统时钟初始化 RELAY_Init();//继电器初始化 LED_Init();//LED KEY_Init();//KEY I2C_Configuration();//I2C初始化 OLED0561_Init(); //OLED初始化---------------" OLED_DISPLAY_8x16_BUFFER(0," WWDG TEST "); //显示字符串 OLED_DISPLAY_8x16_BUFFER(4," RESET! "); //显示字符串 delay_ms(800); // OLED_DISPLAY_8x16_BUFFER(4," "); //显示字符串 WWDG_Init(); //初始化并启动独立看门狗 while(1){ delay_ms(54); //用延时找到喂狗的窗口时间 避开计数初始值到上窗口边界这段时间 WWDG_Feed(); //喂狗 if(!GPIO_ReadInputDataBit(KEYPORT,KEY1)){ delay_s(2); //延时2秒,使程序不能喂狗而导致复制 } } }
定时器的3种功能 捕获器:测量波形的频率和宽度 比较器:分为模拟比较器和输出比较器 模拟比较器:比较两组输入电压的大小(STM32F103无此功能) 输出比较器:产生可调频率和可调占空比的脉冲波形 PWM:脉宽调制器,产生固定频率但占空比可调的脉冲波形 普通定时器 定时器可以用于独立时间计时功能,原理和嘀嗒定时器、看门狗基本相同 定时时间到时,可等待CPU检查标志位(查寻方式),或产生“定时器中断” —般都是让定时器产生中断 捕获器 捕获什么? 输入接口的电平变化(上升沿或下降沿) 上升沿:从低电平到高电平 下降沿:从高电平到低电平 有什么用? 可测量脉冲的宽度,或者测量脉冲频率 宽度 T1是上沿捕获的定时器值 T2是下沿捕获的定时器值 T2-T1=高电平宽度值 频率 T1是第1次上沿捕获值 T2是第2次上沿捕获值 T2-T1=一个周期时间值(频率) 工作过程! 当接口产生上升沿或下降沿时,将当前定时器值保存 输出比较器 可输出脉冲,可调占空比和频率 每一个周期的长度都可以不同 每一个周期内的占空比都可以不同 PWM只能调占空比(也是可以通过程序调频率,但不方便随时调) 输出比较器可随时调占空比和频率 输出比较器主要用于步进电机、伺服电机的控制
定时器中断测试程序
新建文件夹
Basic文件夹——>tim文件夹——>tim.c tim.h
tim.h
#ifndef __PWM_H #define __PWM_H #include "sys.h" void TIM3_Init(u16 arr,u16 psc); void TIM3_NVIC_Init (void); #endif
tim.c
#include "led.h" //因在中断处理函数中用到LED驱动 #include "tim.h" //定时器时间计算公式Tout = ((重装载值+1)*(预分频系数+1))/时钟频率; //例如:1秒定时,重装载值=9999,预分频系数=7199 void TIM3_Init(u16 arr,u16 psc){ //TIM3 初始化 arr重装载值 psc预分频系数 TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStrue; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);//使能TIM3 TIM3_NVIC_Init (); //开启TIM3中断向量 TIM_TimeBaseInitStrue.TIM_Period=arr; //设置自动重装载值 TIM_TimeBaseInitStrue.TIM_Prescaler=psc; //预分频系数 TIM_TimeBaseInitStrue.TIM_CounterMode=TIM_CounterMode_Up; //计数器向上溢出 TIM_TimeBaseInitStrue.TIM_ClockDivision=TIM_CKD_DIV1; //时钟的分频因子,起到了一点点的延时作用,一般设为TIM_CKD_DIV1 TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStrue); //TIM3初始化设置 TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);//使能TIM3中断 TIM_Cmd(TIM3,ENABLE); //使能TIM3 } void TIM3_NVIC_Init (void){ //开启TIM3中断向量 NVIC_InitTypeDef NVIC_InitStructure; NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x3; //设置抢占和子优先级 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x3; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); } void TIM3_IRQHandler(void){ //TIM3中断处理函数 if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET){ //判断是否是TIM3中断 TIM_ClearITPendingBit(TIM3, TIM_IT_Update); //此处写入用户自己的处理程序 GPIO_WriteBit(LEDPORT,LED1,(BitAction)(1-GPIO_ReadOutputDataBit(LEDPORT,LED1))); //取反LED1 } }
main.c
#include "stm32f10x.h" //STM32头文件 #include "sys.h" #include "delay.h" #include "relay.h" #include "oled0561.h" #include "led.h" #include "key.h" #include "tim.h" int main (void){//主程序 delay_ms(500); //上电时等待其他器件就绪 RCC_Configuration(); //系统时钟初始化 RELAY_Init();//继电器初始化 LED_Init();//LED KEY_Init();//KEY I2C_Configuration();//I2C初始化 OLED0561_Init(); //OLED初始化---------------" OLED_DISPLAY_8x16_BUFFER(0," TIM TEST "); //显示字符串 TIM3_Init(9999,7199);//定时器初始化,定时1秒(9999,7199) while(1){ //写入用户的程序 //LED1闪烁程序在TIM3的中断处理函数中执行 } }
CRC(循环冗余校验)计算单元 使用一个固定的多项式发生器,从一个32位的数据字产生一个CRC码在众多的应用中,基于CRC的技术被用于验证数据传输或存储的一致性 在EN/IEC 60335-1标准的范围内,它提供了一种检测闪存存储器错误的手段,CRC计算单元可以用于实时地计算软件的签名,并与在链接和生成该软件时产生的签名对比。 √CRC是用于数据正确性校验的 √由一个32位的数据字产生√可应用在FALSH检测 √可用于软件签名及对比 特点:写入和读出都是同一个寄存器,但内容却不同
main.c
#include "stm32f10x.h" //STM32头文件 #include "sys.h" #include "delay.h" #include "relay.h" #include "oled0561.h" #include "led.h" #include "key.h" int main (void){//主程序 u32 a,b; u8 c; u32 y[3]={0x87654321,0x98765432,0x09876543}; delay_ms(500); //上电时等待其他器件就绪 RCC_Configuration(); //系统时钟初始化 RELAY_Init();//继电器初始化 LED_Init();//LED KEY_Init();//KEY I2C_Configuration();//I2C初始化 OLED0561_Init(); //OLED初始化---------------" OLED_DISPLAY_8x16_BUFFER(0," CRC TEST "); //显示字符串 RCC_AHBPeriphClockCmd(RCC_AHBPeriph_CRC, ENABLE);//开启CRC时钟 while(1){ CRC_ResetDR();//复位CRC,需要清0重新计算时先复位 CRC_CalcCRC(0x12345678);//CRC计算一个32位数据。参数:32位数据。返回值:32位计算结果 CRC_CalcCRC(0x23456789);//CRC计算一个32位数据。参数:32位数据。返回值:32位计算结果 a = CRC_CalcCRC(0x34567890);//CRC计算一个32位数据。参数:32位数据。返回值:32位计算结果 CRC_ResetDR();//复位CRC,需要清0重新计算时先复位 b = CRC_CalcBlockCRC(y,3);//CRC计算一个32位数组。参数:32位数组名,数组长度。返回值:32位计算结果 CRC_SetIDRegister(0x5a);//向独立寄存器CRC_IDR写数据。参数:8位数据。 c = CRC_GetIDRegister();//从独立寄存器CRC_IDR读数据。返回值:8位数据。 //此时,a存放的是3个独立数的CRC结果。(32位) //b存放的是数组y中3个数据CRC计算结果。(32位) //c存放的是我们写入的独立寄存器数据0x5a。(8位) } } // 以下是CRC固件库函数,可在主程序中直接调用 // // RCC_AHBPeriphClockCmd(RCC_AHBPeriph_CRC, ENABLE);//开启CRC时钟,主程序开始时调用 // CRC_ResetDR();//复位CRC,需要清0重新计算时先复位 // uint32_t CRC_CalcCRC(uint32_t Data);//CRC计算一个32位数据。参数:32位数据。返回值:32位计算结果 // uint32_t CRC_CalcBlockCRC(uint32_t pBuffer[], uint32_t BufferLength);//CRC计算一个32位数组。参数:32位数组名,数组长度。返回值:32位计算结果 // uint32_t CRC_GetCRC(void);//从CRC中读出计算结果。返回值:32位计算结果。 // void CRC_SetIDRegister(uint8_t IDValue);//向独立寄存器CRC_IDR写数据。参数:8位数据。 // uint8_t CRC_GetIDRegister(void);//从独立寄存器CRC_IDR读数据。返回值:8位数据。
stm32f10x_crc. c包含了CRC的固件库函数
芯片ID √ 96位ID编码 √可读出3个32位数据,或8个8位数据 √可以以字节(8位)为单位读取,也可以以半字(16位)或者全字(32位)读取 √每个芯片编码是唯一的,出厂时固化,不可修改 √ 可用于产品序列号 √用来作为密码,提高安全性 √用来保护程序的不可复制
main.c
#include "stm32f10x.h" //STM32头文件 #include "sys.h" #include "delay.h" #include "relay.h" #include "oled0561.h" #include "led.h" #include "key.h" #include "usart.h" int main (void){//主程序 u32 ID[3]; delay_ms(500); //上电时等待其他器件就绪 RCC_Configuration(); //系统时钟初始化 RELAY_Init();//继电器初始化 LED_Init();//LED KEY_Init();//KEY USART1_Init(115200); //串口初始化(参数是波特率) I2C_Configuration();//I2C初始化 OLED0561_Init(); //OLED初始化---------------" OLED_DISPLAY_8x16_BUFFER(0," CHIP ID TEST "); //显示字符串 ID[0] = *(__IO u32 *)(0X1FFFF7E8); //读出3个32位ID 高字节 ID[1] = *(__IO u32 *)(0X1FFFF7EC); // ID[2] = *(__IO u32 *)(0X1FFFF7F0); // 低字节 //08表示后面的数据不足8位就补0显示 printf("ChipID: %08X %08X %8X \r\n",ID[0],ID[1],ID[2]); //从串口输出16进制ID if(ID[0]==0x066EFF34 && ID[1]==0x3437534D && ID[2]==0x43232328){ //检查ID是否匹配 printf("chipID OK! \r\n"); //匹配 }else{ printf("chipID error! \r\n"); //不同 } while(1){ } }
1.仿真 仿真接口有JTAG、SW接口,仿真器又有ST-LINK、J-LINK等 还有纯软件仿真Proteus等 2.HEL库 3.内置USB接口 USB鼠标、键盘、U盘 4.显示屏 除OLED之外,还能外扩LCD1602、12864等 显示屏的类型还有VOG屏、TFT屏等 每种屏的接口也分好多种 5.定时器的复杂功能 TIM1高级定时器的使用 单脉冲模式 输出比较器的使用 捕获器的使用 定时器的DMA设置 6.中断的复杂功能 中断嵌套应用与优先级问题 外部中断的端口映射问题 7.单片机内部功能 WIFI、蓝牙、GPS模块、2.4G模块、彩屏的人机界面、RTOS嵌入式操作系统....