基于STM32F103的RTC功能实现
前言:
最近心血来潮,想用stm32f103c8t6这块小板子实现定时的功能,但是发现网上没有太多的资料,所以自己弄了一个。
有几点需要大家注意的是:
由于这个核心板没有外部晶振,所以在RTC初始化时用的是LSI(内部低速晶振),频率约为40KHZ。
由于没有纽扣电池,故断电后无法继续计时。
实现功能:
- 串口显示日期和时间
- 串口设置日期和时间
- 串口设置闹钟
所需元器件:
- stm32f103c8t6核心板
- USB转串口模块
实物展示:
结果展示:
代码实现:
main,c文件
#include "sys.h"int main(void)
{delay_init(); //延时函数初始化LED_GPIO_Config(); //LED引脚配置My_USART1(); //串口初始化printf("串口初始化完成\r\n");RTC_Init(); //RTC初始化//RTC_Alarm_Set(2021,12,30,17,35,20); //闹钟设置while(1){GPIO_ResetBits(GPIOC, GPIO_Pin_13);delay_ms(500);GPIO_SetBits( GPIOC, GPIO_Pin_13); delay_ms(500);}
}
RTC.C文件
#include "rtc.h"
#include "sys.h"
#include "string.h"
#include "led.h"
#include <stdlib.h>
const char *pt = __TIME__; //20:15:05
const char *pd = __DATE__; //Dec 30 2021u8 month[13][5] = {"NUL","Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
struct SET_ALARM alarm;_calendar calendar;//时钟结构体static void RTC_NVIC_Config(void)
{ NVIC_InitTypeDef NVIC_InitStructure;NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn; //RTC全局中断NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //先占优先级1位,从优先级3位NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //先占优先级0位,从优先级4位NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能该通道中断NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
}
/*******************************************************************************
* 函 数 名 : RTC_Init_LSI
* 函数功能 : RTC初始化
* 输 入 : 无
* 输 出 : 0,初始化成功1,LSI开启失败
解决复位之后RTC_WaitForSynchro();卡死问题:此句在if外面开启时钟,RCC_LSICmd(ENABLE);
内部晶振低速时钟40KHZ
注意:使用内部低速时钟断电后无法继续走时,即使有备用电池也不行
LSI需由主电源VDD供电,而VBAT只能使LSE起振。
*******************************************************************************/
u8 RTC_Init_LSI(void)
{//检查是不是第一次配置时钟u8 temp=0;RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE); //使能PWR和BKP外设时钟PWR_BackupAccessCmd(ENABLE); //使能后备寄存器访问RCC_LSICmd(ENABLE); //设置内部低速晶振(LSI)if (BKP_ReadBackupRegister(BKP_DR1) != 0x5050) //从指定的后备寄存器中读出数据:读出了与写入的指定数据不相乎{BKP_DeInit(); //复位备份区域//RCC_LSEConfig(RCC_LSE_ON); //设置外部低速晶振(LSE),使用外设低速晶振while (RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET&& temp < 250) //检查指定的RCC标志位设置与否,等待低速晶振就绪{temp++;delay_ms(10);}if(temp>=250)return 1;//初始化时钟失败,晶振有问题//RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); //设置RTC时钟(RTCCLK),选择LSE作为RTC时钟RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI); //设置RTC时钟(RTCCLK),选择LSI作为RTC时钟RCC_RTCCLKCmd(ENABLE); //使能RTC时钟RTC_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成RTC_WaitForSynchro(); //等待RTC寄存器同步RTC_ITConfig(RTC_IT_SEC|RTC_IT_ALR, ENABLE); //使能RTC秒中断、闹钟中断RTC_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成RTC_EnterConfigMode();/// 允许配置//RTC_SetPrescaler(32767); //设置RTC预分频的值RTC_SetPrescaler(40000); //设置RTC预分频的值RTC_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成//RTC_Set(2017,3,6,0,0,0); //设置时间get_time();RTC_Set(calendar.w_year+2000-1 ,calendar.w_month,calendar.w_date,calendar.hour,calendar.min,calendar.sec); //设置时间RTC_ExitConfigMode(); //退出配置模式BKP_WriteBackupRegister(BKP_DR1, 0X5050); //向指定的后备寄存器中写入用户程序数据}else//系统继续计时{RTC_WaitForSynchro(); //等待最近一次对RTC寄存器的写操作完成RTC_ITConfig(RTC_IT_SEC|RTC_IT_ALR, ENABLE); //使能RTC秒中断、闹钟中断RTC_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成}RTC_NVIC_Config();//RCT中断分组设置RTC_Get();//更新时间return 0; //ok
}//RTC时钟中断
//每秒触发一次
void RTC_IRQHandler(void)
{ if (RTC_GetITStatus(RTC_IT_SEC) != RESET)//秒钟中断{ RTC_Get();//更新时间 printf("RTC Time:%d-%d-%d %d:%d:%d\r\n",calendar.w_year,calendar.w_month,calendar.w_date,calendar.hour,calendar.min,calendar.sec);//输出闹铃时间 }if(RTC_GetITStatus(RTC_IT_ALR)!= RESET)//闹钟中断{RTC_ClearITPendingBit(RTC_IT_ALR); //清闹钟中断 RTC_Get(); //更新时间 printf("Alarm Time:%d-%d-%d %d:%d:%d\r\n",calendar.w_year,calendar.w_month,calendar.w_date,calendar.hour,calendar.min,calendar.sec);//输出闹铃时间 } RTC_ClearITPendingBit(RTC_IT_SEC|RTC_IT_OW); //清闹钟中断RTC_WaitForLastTask();
}
//判断是否是闰年函数
//月份 1 2 3 4 5 6 7 8 9 10 11 12
//闰年 31 29 31 30 31 30 31 31 30 31 30 31
//非闰年 31 28 31 30 31 30 31 31 30 31 30 31
//输入:年份
//输出:该年份是不是闰年.1,是.0,不是
u8 Is_Leap_Year(u16 year)
{ if(year%4==0) //必须能被4整除{ if(year%100==0) { if(year%400==0)return 1;//如果以00结尾,还要能被400整除 else return 0; }else return 1; }else return 0;
} //月份数据表
u8 const table_week[12]={0,3,3,6,1,4,6,2,5,0,3,5}; //月修正数据表
//平年的月份日期表
const u8 mon_table[12]={31,28,31,30,31,30,31,31,30,31,30,31};/*******************************************************************************
* 函 数 名 : RTC_Set
* 函数功能 : RTC设置日期时间函数(以1970年1月1日为基准,把输入的时钟转换为秒钟)1970~2099年为合法年份
* 输 入 : syear:年 smon:月 sday:日hour:时 min:分 sec:秒
* 输 出 : 0,成功1,失败
*******************************************************************************/
u8 RTC_Set(u16 syear,u8 smon,u8 sday,u8 hour,u8 min,u8 sec)
{u16 t;u32 seccount=0;if(syear<1970||syear>2099)return 1; for(t=1970;t<syear;t++) //把所有年份的秒钟相加{if(Is_Leap_Year(t))seccount+=31622400;//闰年的秒钟数else seccount+=31536000; //平年的秒钟数}smon-=1;for(t=0;t<smon;t++) //把前面月份的秒钟数相加{seccount+=(u32)mon_table[t]*86400;//月份秒钟数相加if(Is_Leap_Year(syear)&&t==1)seccount+=86400;//闰年2月份增加一天的秒钟数 }seccount+=(u32)(sday-1)*86400;//把前面日期的秒钟数相加 seccount+=(u32)hour*3600;//小时秒钟数seccount+=(u32)min*60; //分钟秒钟数seccount+=sec;//最后的秒钟加上去RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE); //使能PWR和BKP外设时钟 PWR_BackupAccessCmd(ENABLE); //使能RTC和后备寄存器访问 RTC_SetCounter(seccount); //设置RTC计数器的值RTC_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成 return 0;
}//初始化闹钟
//以1970年1月1日为基准
//1970~2099年为合法年份
//syear,smon,sday,hour,min,sec:闹钟的年月日时分秒
//返回值:0,成功;其他:错误代码.
u8 RTC_Alarm_Set(u16 syear,u8 smon,u8 sday,u8 hour,u8 min,u8 sec)
{u16 t;u32 seccount=0;if(syear<1970||syear>2099)return 1; for(t=1970;t<syear;t++) //把所有年份的秒钟相加{if(Is_Leap_Year(t))seccount+=31622400;//闰年的秒钟数else seccount+=31536000; //平年的秒钟数}smon-=1;for(t=0;t<smon;t++) //把前面月份的秒钟数相加{seccount+=(u32)mon_table[t]*86400;//月份秒钟数相加if(Is_Leap_Year(syear)&&t==1)seccount+=86400;//闰年2月份增加一天的秒钟数 }seccount+=(u32)(sday-1)*86400;//把前面日期的秒钟数相加 seccount+=(u32)hour*3600;//小时秒钟数seccount+=(u32)min*60; //分钟秒钟数seccount+=sec;//最后的秒钟加上去 //设置时钟RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE); //使能PWR和BKP外设时钟 PWR_BackupAccessCmd(ENABLE); //使能后备寄存器访问 //上面三步是必须的!RTC_SetAlarm(seccount);RTC_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成 return 0;
}//得到当前的时间
//返回值:0,成功;其他:错误代码.
u8 RTC_Get(void)
{static u16 daycnt=0;u32 timecount=0; u32 temp=0;u16 temp1=0; timecount=RTC_GetCounter(); temp=timecount/86400; //得到天数(秒钟数对应的)if(daycnt!=temp)//超过一天了{ daycnt=temp;temp1=1970; //从1970年开始while(temp>=365){ if(Is_Leap_Year(temp1))//是闰年{if(temp>=366)temp-=366;//闰年的秒钟数else {temp1++;break;} }else temp-=365; //平年 temp1++; } calendar.w_year=temp1;//得到年份temp1=0;while(temp>=28)//超过了一个月{if(Is_Leap_Year(calendar.w_year)&&temp1==1)//当年是不是闰年/2月份{if(temp>=29)temp-=29;//闰年的秒钟数else break; }else {if(temp>=mon_table[temp1])temp-=mon_table[temp1];//平年else break;}temp1++; }calendar.w_month=temp1+1; //得到月份calendar.w_date=temp+1; //得到日期 }temp=timecount%86400; //得到秒钟数 calendar.hour=temp/3600; //小时calendar.min=(temp%3600)/60; //分钟 calendar.sec=(temp%3600)%60; //秒钟calendar.week=RTC_Get_Week(calendar.w_year,calendar.w_month,calendar.w_date);//获取星期 return 0;
} //获得现在是星期几
//功能描述:输入公历日期得到星期(只允许1901-2099年)
//输入参数:公历年月日
//返回值:星期号
u8 RTC_Get_Week(u16 year,u8 month,u8 day)
{ u16 temp2;u8 yearH,yearL;yearH=year/100; yearL=year%100; // 如果为21世纪,年份数加100 if (yearH>19)yearL+=100;// 所过闰年数只算1900年之后的 temp2=yearL+yearL/4;temp2=temp2%7; temp2=temp2+day+table_week[month-1];if (yearL%4==0&&month<3)temp2--;return(temp2%7);
} void get_time()
{//Dec 3 2021if( pd[4] == ' ' ){calendar.w_date = pd[5]-'0';//得到日}else //Dec 30 2021{calendar.w_date= (pd[4]-'0')*10 + (pd[5]-'0');//得到日}calendar.w_year = (pd[9]-'0')*10 + (pd[10]-'0');//得到年 //printf("年:%d\r\n",calendar.w_year );u8 i;for(i = 1; i <= 12; i++){if(strcmp((const char *)pd, (char *)month[i]) == 0){break;//找到月份了}}calendar.w_month = i;//得到月 calendar.hour = (pt[0]-'0')*10 + (pt[1]-'0');//得到小时calendar.min = (pt[3]-'0')*10 + (pt[4]-'0');//得到分钟calendar.sec = (pt[6]-'0')*10 + (pt[7]-'0');//得到秒
}
my_usart1.c文件
#include "sys.h"
#include "my_usart1.h"
#include <string.h>
#include <stdlib.h>void My_USART1(void)
{//定义结构体变量,注意:只能放在{后面GPIO_InitTypeDef GPIO_InitStruct;USART_InitTypeDef USART1_InitStruct;NVIC_InitTypeDef NVIC_InitStruct;/*1串口时钟、GPIO时钟初始化*/RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE);/*2GPIOA端口模式设置*///配置引脚TXGPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP; //推挽复用输出GPIO_InitStruct.GPIO_Pin = USART1_GPIO_PIN_TX; //PA9GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStruct);//配置引脚RXGPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入GPIO_InitStruct.GPIO_Pin = USART1_GPIO_PIN_RX; //PA10//GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStruct);/*3串口参数初始化*/USART1_InitStruct.USART_BaudRate = 9600; //波特率USART1_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //流控USART1_InitStruct.USART_Mode = USART_Mode_Tx |USART_Mode_Rx ; //串口模式USART1_InitStruct.USART_Parity = USART_Parity_No; //校验位USART1_InitStruct.USART_StopBits = USART_StopBits_1 ; //停止位USART1_InitStruct.USART_WordLength = USART_WordLength_8b; //数据位USART_Init(USART1,&USART1_InitStruct);/*4开启中断并且初始化NVIC*/USART_ITConfig( USART1, USART_IT_RXNE, ENABLE);//开启接收中断NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn; //选择中断源NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1; //抢占优先级NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1; //响应优先级NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; //中断使能NVIC_Init(&NVIC_InitStruct); /*5使能串口*/USART_Cmd(USART1,ENABLE);/*6编写中断处理函数*/
}/*实现发送字符串的功能描述:
依次发送字符串中的字符,每发送一个检查下TXE标志位,修改库函数中的USART_SendData()函数即可
发送完全部字符以后,最后检查TC标志位 ,*/
void USART_SendByte(USART_TypeDef* USARTx, uint16_t Data)
{/* Check the parameters */assert_param(IS_USART_ALL_PERIPH(USARTx));assert_param(IS_USART_DATA(Data)); /* Transmit Data */USARTx->DR = (Data & (uint16_t)0x01FF);while( USART_GetFlagStatus(USARTx, USART_FLAG_TXE)==RESET);
}void USART_SendString(USART_TypeDef* USARTx, char *str)
{ while(*str!='\0'){USART_SendByte(USARTx,*str++);}while( USART_GetFlagStatus(USARTx, USART_FLAG_TC)==RESET);
}uint8_t USART_ReceiveByte(USART_TypeDef* USARTx)
{while(USART_GetFlagStatus(USARTx, USART_FLAG_RXNE)==RESET);return (uint8_t) USART_ReceiveData(USART1);}static volatile uint8_t g_usart1_buf[128]={0};
static volatile uint32_t g_usart1_cnt=0;
void USART1_IRQHandler(void) //串口1中断服务程序
{uint8_t d=0;int i = 0;u16 alarm_buf[64]={0};u16 rtc_buf[64]={0};if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中断(接收到的数据必须是0x0d 0x0a结尾){//接收串口数据d = USART_ReceiveData(USART1); g_usart1_buf[g_usart1_cnt] = d;g_usart1_cnt++;//设置闹钟if(d == 'A'|| g_usart1_cnt>= sizeof(g_usart1_buf)){ char *s = strtok((char *)g_usart1_buf,"- :"); //分割符是- :while(s!=NULL){ alarm_buf[i] = atoi(s); //2022-1-10 23:50:5Ai++;s = strtok(NULL,"- :");g_usart1_cnt = 0;}RTC_Alarm_Set(alarm_buf[0],alarm_buf[1],alarm_buf[2],alarm_buf[3], alarm_buf[4],alarm_buf[5]); //闹钟设置printf("%d-%d-%d %d:%d:%d 设置闹钟成功!\r\n",alarm_buf[0],alarm_buf[1],alarm_buf[2],alarm_buf[3],alarm_buf[4],alarm_buf[5]);} //设置时间else if(d == 'R'|| g_usart1_cnt>= sizeof(g_usart1_buf)){ char *s = strtok((char *)g_usart1_buf,"- :"); //分割符是- :while(s!=NULL){ rtc_buf[i] = atoi(s); //2022-1-10 23:50:5Ri++;s = strtok(NULL,"- :");g_usart1_cnt = 0;}RTC_Set(rtc_buf[0],rtc_buf[1],rtc_buf[2],rtc_buf[3], rtc_buf[4],rtc_buf[5]); //设置时间printf("%d-%d-%d %d:%d:%d 设置时间成功!\r\n",rtc_buf[0],rtc_buf[1],rtc_buf[2],rtc_buf[3],rtc_buf[4],rtc_buf[5]);} //清空串口接收中断标志位USART_ClearITPendingBit(USART1, USART_IT_RXNE);}
} /*不勾选微库则需要这个*/
#pragma import(__use_no_semihosting)
struct __FILE
{int handle;
};FILE __stdout;
void _sys_exit(int x)
{x = x;
}///重定向c库函数printf到串口,重定向后可使用printf函数
int fputc(int ch, FILE *f)
{/* 发送一个字节数据到串口 */USART_SendData(USART1, (uint8_t) ch);/* 等待发送完毕 */while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); return (ch);
}///重定向c库函数scanf到串口,重写向后可使用scanf、getchar等函数
int fgetc(FILE *f)
{/* 等待串口输入数据 */while (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET);return (int)USART_ReceiveData(USART1);
}
追加内容:
如果有3V纽扣电池和32.768KHz的石英晶振,就可以实现断电后RTC继续走时的功能。
根据数据手册可知,外部低速时钟电路可以这样搭建:
其中 CL1 和 CL2 为 5pF~15pF 之间的瓷介电容器,OSC32_IN为引脚PC14,OSC32_OUT为引脚PC15。
纽扣电池电路可以这样搭建:
当接电池和有v3.3电源时,就会选择v3.3供电。当接电池和没有v3.3电源时,就会选择电池供电,即3v3掉电后RTC也能照常工作,备用的纽扣电池。当不接电池和有v3.3电源时也会选择v3.3供电。
详细内容请看STM32 VBAT外围电路接法详解
代码实现如下:
除RTC的初始化不一样外,其他都一样。
/*******************************************************************************
* 函 数 名 : RTC_Init_LSE
* 函数功能 : RTC初始化
* 输 入 : 无
* 输 出 : 0,初始化成功1,LSE开启失败
外部低速时钟
注意:使用外部低速时钟断电后如果有备用电池可以继续走时
*******************************************************************************/
u8 RTC_Init_LSE(void)
{//检查是不是第一次配置时钟u8 temp=0;RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE); //使能PWR和BKP外设时钟PWR_BackupAccessCmd(ENABLE); //使能后备寄存器访问//RCC_LSICmd(ENABLE); //设置内部低速晶振(LSI)if (BKP_ReadBackupRegister(BKP_DR1) != 0x6060) //从指定的后备寄存器中读出数据:读出了与写入的指定数据不相乎{BKP_DeInit(); //复位备份区域RCC_LSEConfig(RCC_LSE_ON); //设置外部低速晶振(LSE),使用外设低速晶振while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET&& temp < 250) //检查指定的RCC标志位设置与否,等待低速晶振就绪{temp++;delay_ms(10);}if(temp>=250)return 1;//初始化时钟失败,晶振有问题RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); //设置RTC时钟(RTCCLK),选择LSE作为RTC时钟//RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI); //设置RTC时钟(RTCCLK),选择LSI作为RTC时钟RCC_RTCCLKCmd(ENABLE); //使能RTC时钟RTC_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成RTC_WaitForSynchro(); //等待RTC寄存器同步RTC_ITConfig(RTC_IT_SEC|RTC_IT_ALR, ENABLE); //使能RTC秒中断、闹钟中断RTC_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成RTC_EnterConfigMode();/// 允许配置RTC_SetPrescaler(32767); //设置RTC预分频的值//RTC_SetPrescaler(40000); //设置RTC预分频的值RTC_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成//RTC_Set(2017,3,6,0,0,0); //设置时间get_time();RTC_Set(calendar.w_year+2000-1 ,calendar.w_month,calendar.w_date,calendar.hour,calendar.min,calendar.sec); //设置时间RTC_ExitConfigMode(); //退出配置模式BKP_WriteBackupRegister(BKP_DR1, 0X6060); //向指定的后备寄存器中写入用户程序数据}else//系统继续计时{RTC_WaitForSynchro(); //等待最近一次对RTC寄存器的写操作完成RTC_ITConfig(RTC_IT_SEC|RTC_IT_ALR, ENABLE); //使能RTC秒中断、闹钟中断RTC_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成}RTC_NVIC_Config();//RCT中断分组设置RTC_Get();//更新时间return 0; //ok
}
最后:
需要代码的可以自行下载。代码下载链接
下载操作:
基于STM32F103的RTC功能实现相关推荐
- 2021校赛基于stm32f103多功能台灯
2021校赛基于stm32f103多功能台灯 起源 又到了一学期一次的校内电子设计大赛,又到了激动人心的时刻每次电子设计大赛都会出现各种大佬展现他们的作品,对于我这种菜鸟也只能默默观望,但是呢,积极参 ...
- 基于STM32的多功能MP3设计 毕业设计(论文)开题报告
中国计量学院 毕业设计(论文)开题报告 学生姓名:卢杰学 号:XXXXXXXXX 专 业:电子科学与技术 班 级:10电子1 设计(论文)题目: 基于STM32的多功能MP3设计 指导教师 ...
- 基于STM32F103的智能门锁系统
基于STM32F103的智能门锁系统 直接说明实现了什么效果 1 指纹解锁(基于AS608) 2 RFID解锁(基于RC522) 3 密码解锁 (基于LCD电容屏触摸控制) 4 蓝牙解锁 (基于HC- ...
- 基于STM32f103的电子秤系统设计
许久前整理的一项课程设计,具备以下资源: 1.论文:25页,近9000字 2.程序:Keil5源程序 3.实物:实测可用 软件程序上传在百度网盘,请自行下载: 链接:https://pan.baidu ...
- 机智云代码移植_IoT开发者 | 基于STM32F103的机智云宠物屋外加4路继电器开源教程...
[ 写在前面 ] 自智云社区开辟IoT开源项目专区以来,一直有IoT开发者在贡献案例.玛莉甄选了一些具有代表性的案例分享给IoT爱好者们,本文亦如此. 若你有好的案例,想和IoT爱好者们分享,欢迎投稿 ...
- 基于STM32F103芯片实现LED灯闪烁
基于STM32F103芯片实现LED灯闪烁 前言 一,寄存器配置 1,时钟控制 2,GPIO端口设置: 二.实际操作 1.具体代码 2.keil5项目运行 3.硬件的连接 4.链接到 mcuisp 串 ...
- 基于STM32F103平台的ADS79xx系列ADC(TI公司)应用方案
目录 第一章 ADS79xx系列芯片特性简介 第二章 芯片内部结构简介 第三章 封装介绍 第四章 硬件布线设计 第五章 基于STM32F103平台的Keil编程 参考文献 第一章 ADS79xx系列芯 ...
- 【基于STM32F103+AS608的智能打卡系统】
基于STM32F103+AS608的智能打卡系统 工程源码链接 链接:https://pan.baidu.com/s/1RRc03nTrcTp--xfQnv2r9Q?pwd=in9p 提取码:in9p ...
- 基于STM32F103的家庭火灾报警及灭火系统(初步)
基于STM32F103的家庭火灾报警及灭火系统 1 绪论 1.1 课题背景 1.2 设计概述 1.3 设计任务分析 2 装置选取总体方案设计 2.1 烟雾检测传感器选型与介绍 2.1.1 烟雾传感器的 ...
最新文章
- FGPM:文本对抗样本生成新方法
- 用PHP删除一条记录mysql,php – 如何使用jquery删除mysql记录
- 电脑的发展史_互联网发展史 硅谷传奇之 IBM
- [html] 说说你对html的嵌套规范的理解,都有哪些规范呢?
- 数据分析(SQL)常见面试题:开窗函数
- django 1.8 官方文档翻译:5-2-2 表单素材 ( Media 类)
- docker 基础之数据管理
- 50mm定焦,f1.8与1.4有什么不同?
- 看《乡村爱情》,秒懂区块链!
- linux uuid挂载磁盘_Linux磁盘设备磁盘设备的UUID标识代码(sda,sdb,sdc…)变化的解决办法...
- linux c++ 时间戳转换,C++时间戳转换成日期时间的步骤和示例代码
- JAVA 逆向工程技术研究日志
- FPGA丨RGB转Ycbcr算法实现
- 超平面与半空间Euclid 球和椭球 超平面分离定理和 支撑超平面定理
- 浪漫七夕—很幸运一路有你
- 深圳南山区学位申请特殊住房需要的材料有哪些
- 目前网页制作的基本语言html,第二讲网页制作基本语言HTML”.ppt
- ROS 罗技手柄控制机器人(仿真和实体机器人)
- java电子报刊网站_采集电子报纸 - 杨尚川的个人页面 - OSCHINA - 中文开源技术交流社区...
- 详解“因果效应估计”