资讯详情

基于STM32的智能篮球测温记分记时系统

1.项目概述(20分)

在21世纪,随着电子信息通信技术的应用和普及,人们对电子技术的要求越来越高。篮球作为一项体育运动,已经进入了人们的生活。为了规范比赛管理,研究篮球比赛温度计时评分系统非常重要。 虽然电子计分器在篮球比赛中很早就被研究和应用,但它通常由模拟电子设备、数字电子设备或模拟和数字混合组成,其稳定性和高精度评分仍存在一些问题。以STM32F103R以单片机为核心的篮球比赛温度计分器,具有体积小、重量轻、能耗低、价格低、可靠性高、抗干扰能力强、使用方便等独特优点。基于STM为了解决这个问题,32智能篮球比赛测温计时系统。系统可测量室温,定期设置赛程,及时刷新A、B双方的成绩,赛程停,报警结束比赛功能。 本项目已使用STM32F103R6单片机,整体设计为主控、矩阵键盘、显示、报警、温度模拟五部分。综合应用STM32中断系统,定时器,计数器,ADC模数转化等知识。 矩阵键盘功能包括加一分、加二分、加三分、减一分、减三分、选A队B复位、启动/暂停、减一分钟、减两分钟、减三分钟、关闭蜂鸣器等。当按下“A在选择A队后,可以加分或减分A队。若此时按1,A队分数加1。当按下“B在选择B队后,就可以加分或减分B队。若此时按3,B队分数加3。当按下“*比赛开始计时或暂停。按#时,复位。当比赛时间为0时,打开蜂鸣器和小灯,按下0,关闭报警的蜂鸣器和小灯。 报警模块主要采用蜂鸣器和LED小灯组成的,当传入为低电平开启蜂鸣器并点亮LED小灯传入高电平关闭蜂鸣器和LED小灯。 通过液晶显示模块LCD1602显示模拟环境温度,修改温度传感器,液晶显示器立即显示最新环境温度。延迟一段时间,进入游戏界面,显示游戏节数,剩余时间,两队得分。 使用了温度模拟模块DS18B20温度传感器可以增减环境温度,并在液晶显示器上显示当前模拟温度。 1、LCD1602液晶显示器可示环境温度,一段时间后显示剩余时间和球队分数。 2.默认比赛为4节,每节10分钟,可以在默认情况下修改比赛时间(比如一节可以修改为5分钟)。 3.每节比赛结束后,蜂鸣器同时报警LED灯亮了。时间可以暂停或复位。 每场比赛都有A、B两支队伍,通过使用矩阵键盘,可以分别对两支队伍进行评分控制。按A就是选A队,然后按1、2、3就可以累积相应的分数。如果不小心得分错误(比如多加分),可以按4、5、6来控制相应的1、2、3分。 本项目主要应用keil5编写代码,proteus设计模拟图,模拟功能的实现。操作矩阵键盘,包括比分修改、时间控制、蜂鸣器和LED小灯负责警报功能,LED液晶显示器负责显示,温度传感器负责模拟当前的环境温度。

2.项目硬件系统设计(30分)

在这里插入图片描述

如图所示,使用的芯片是STM32F103R6.采用显示模块LCD1602液晶显示器通过输入矩阵键盘来控制比赛时间和分数LCD显示液晶显示屏。在液晶显示器中,温度传感器可以模拟环境温度。PA0-PA7引脚接LCD液晶显示器162D0-D7,PB8引脚接RS,PC13接RW,PB9接E。PC0-PC7引脚分别连接矩阵键盘,PC8引脚接蜂鸣器。PB4引脚连接温度传感器DQ引脚。

Proteus仿真图:

1)内核架构–CM3内核架构:

STM32F103是一个ARM单片机,嵌有一个Cortex-M3(简称CM3)以处理器为核心。 CM三条总线通过总线矩阵和STM32F主要部件与外设相连。 STM32F103的架构包括CM除内核以外的内核架构和其他结构。 2)GPIO:(General Purpose Input Output,通用输入输出接口)MCU连接外部电路和设备的基本外设。也就是常说的端口或管脚。 GPIO软件可配置8种工作方式: 1.浮动输入:上下拉电阻断开,用于输入不确定高低电平。(复位后处于这种状态 2.上拉输入:上拉电阻接通,默认高电平输入。 3.下拉输入:下拉电阻接通,默认低电平输入。 4.模拟输入:施密特触发器截止日期,常用于模拟输入AD转换 5.泄漏输出:上部MOS如果不工作,只能输出低电平,不能输出高电平。如果要输出高电平,需要外拉。用于输出电平转换和线路和功能。 6.推拉输出:上下:MOS用于大功率驱动的输出。 7.推挽式复用输出功能:复用功能下的推挽输出。 8.开漏复用输出功能:复用功能下的开漏输出。 3)NVIC中断控制器:(Nested Vectored Interrupt Controller,NVIC)位于CM中断系统硬件设施用于管理和配置中断。 NVIV的功能:(硬件 控制寄存器组成) 1.管理中断源2。保存中断申请信号3。优先判断中断嵌套4。屏蔽中断5 4)EXTI控制器:主要用于管理片外引脚中断和事件控制。 EXTI控制器是片上外设,可以管理 16路外引脚中断 和 4路事件 的控制, 共20 路输入。 EXTI --外部中断/事件线路映像: 80个通用I/O端口:外部中断或事件输入线可连接到16个外部中断/事件线。使用时必须设置AFIO功能,并使其时钟。(可以是中断或事件) 四条专用线: 1、EXTI线16连接到PVD输出(中断)。 2、EXTI线17连接到RTC闹钟事件。 3、EXTI线18连接到USB唤醒事件。 4、EXTI线19连接到以太网唤醒事件 注释:PVD(可编程电压监测器),可管理上电复位和断电中断。 5)ADC模数转化:ADC 的转换分为 2 通道组:规则通道组和注入通道组。规则通道相当于您正常运行的程序,而注入通道相当于中断。规则通道的转换可以打断注入通道的转换, 规则通道只有在注入通道转换后才能继续转换。 ADC 的规则规则通道组最多包含 16 注入通道组最多包含个转换 4 个通道。 规则通道组:规则通道及其转换顺序ADC_SQRx选择寄存器,规则组转换的总数应写入ADC_SQR1寄存器的L[3:0]中。 注入通道组:注入组及其转换顺序ADC_JSQR选择寄存器,注入组转换的总数应写入ADC_JSQR寄存器的L[1:0]中。 2.3 矩阵键盘模块原理 该按钮由一组独立按钮组成,由于结构简单,价格低廉,选用弹性按钮。同时,每个按钮单独连接芯片对应的引脚,简化了电路设计。该设计有16个独立的弹性键来控制分数的加减、计时的开始和结束。均对应GPIO口直接连接,一切GPIO口设置为上拉输入电平触发。一旦按下小键,相应的引脚与地面连接成低电平。当程序进入按钮查询时,为低电平,表示按钮按下,按钮弹起后为高电平。

2.4 LCD1602液晶显示器模块原理 液晶显示的原理是利用液晶的物理特性,通过电压控制显示区域,有电就显示图形。液晶显示器厚度薄,适用于大型集成电路直接驱动,易于实现全彩显示。目前已广泛应用于便携式计算机、数字相机、PDA移动通信工具等许多领域。 液晶显示模块是一个缓慢的显示设备,因此在执行每个指令之前,必须确认该模块的忙标志为低电平,表示不忙,否则该指令将无效。在显示字符时,输入显示字符地址,即告诉模块在哪里显示字符。所以要忙着等待。

引脚说明: 第1脚:VSS为地电源。 第2脚:VDD接5V正电源。 第3脚:VL对于液晶显示器的对比度调整端,连接正电源时对比度最弱,接地时对比度最高,对比度过高时会产生鬼影K调整电位器的对比度。 第4脚:RS选择寄存器,高电平时选择数据寄存器,低电平时选择指令寄存器。 第5脚:R/W为了读写信号线,高电平时读写操作,低电平时写当RS和R/W在低电平时,可以写下指令或显示地址RS为低电平 R/W平时为高电读忙信号,RS为高电平R/W通常可以为低电写入数据。 第6脚:E当E端从高电平跳转到低电平时,液晶模块执行命令。 第7~14脚:D0~D7是8位双向数据线。 15脚:背光源正极。 16脚:背光源负极。 需要这个项目LCD倒计时显示1602液晶显示器,也需要显示A、B两队分数。LCD液晶显示器162D0-D7分别接STM32F103R6的PA0-PA7引脚,RS接PB8引脚,RW接PC13。 2.5 蜂鸣器模块原理 蜂鸣器是一种综合电子信息器,采用直流电压供电,广泛应用于计算机、打印机、复印机、报警器、电子玩具、汽车电子设备、电话、定时器等电子产品。蜂鸣器主要分为压电蜂鸣器和电磁蜂鸣器。当每一节比赛计时结束时,该系统使用蜂鸣器提示时间=0.(设置为低电平)蜂鸣器报警,按下0键后关闭蜂鸣器。

2.6 LED灯模块原理 有一个系统LED小灯,正极电源。当系统直接查询比赛截止日期时,立即使用STM32相应GPIO口为低电平,点亮相应的小灯。保持系统LED直到按下复位键,灯才会熄灭。

2.7 温度传感器模块原理 有一个系统DS18B20温度传感器,要用于模拟当前环境温度,并在液晶显示器上显示当前模拟温度。DS18B20适应电压范围宽,电压范围:3.0~5.5V,在寄生电源方式下可由数据线供电独特的单线接口方式,DS18B20在与微处理器连接时仅需要一条线即可实现微处理器与DS18B20的双向通讯DS18B20支持多点组网功能,多个DS18B20可以并联在唯一的三线上,实现组网多点测温DS18B20在使用中不需要任何外围元件,全部传感元件及转换电路集成在形如一只三极管的集成电路内测温范围-55℃~+125℃,在-10~+85℃时精度为±0.5℃可编程的分辨率为9~12位,对应的可分辨温度分别为0.5℃、0.25℃、0.125℃和0.0625℃,可实现高精度测温在9位分辨率时最多在93.75ms内把温度转换为数字,12位分辨率时最多在750ms内把温度值转换为数字,速度快测量结果直接输出数字温度信号。

2.8 系统定时器控制部件设计 定时控制部件是在规定的时刻发出各种操作所需的全部内部和外部控制信号,使各功能元件协调工作,完成指令所规定的功能。主要任务是产生一个工作时序,其工作需要时钟电路提供一个工作频率,外接时钟源可构成时钟电路。单片机的生产工艺不同,时钟的产生方式也不同有内部和外部时钟产生两种时钟方式,本系统采用的是内部时钟产生方式,输入输出两端跨接晶体或陶瓷谐振器,于内部反向器构成稳定的自激振荡器。其发出的脉冲直接送入片内的定时控制部件。

3、系统软件体系设计(30分)

本项目主要子模块为定时器中断模块,矩阵键盘模块,显示模块,警报检测模块,温度传感器AD转化模块 总流程图:

定时器采用内中断模式,实现步骤为: 1、定时器时钟 RCC_APB1PeriphClockCmd(); 2、初始化定时器,配置ARR,PSC。 TIM_TimeBaseInit(); 3、开启定时器中断,配置NVIC Void TIM_ITCongfig(); NVIC _Init(); 4、使能定时器。TIM_Cmd(); 5、编写中断函数

static void GENERAL_TIM2_Mode_Config(void) { // 开启定时器时钟,即内部时钟CK_INT=8M GENERAL_TIM2_APBxClock_FUN(GENERAL_TIM2_CLK,ENABLE); TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; // 开启定时器时钟,即内部时钟CK_INT=8M GENERAL_TIM2_APBxClock_FUN(GENERAL_TIM2_CLK, ENABLE); // 自动重装载寄存器的值,累计TIM_Period+1个频率后产生一个更新或者中断 #ifdef SIMULATION TIM_TimeBaseStructure.TIM_Period = GENERAL_TIM2_Period + 1; #else TIM_TimeBaseStructure.TIM_Period = GENERAL_TIM2_Period; #endif // 时钟预分频数 TIM_TimeBaseStructure.TIM_Prescaler = GENERAL_TIM2_Prescaler; // 时钟分频因子 ,没用到不用管 TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; // 计数器计数模式,设置为向上计数 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // 重复计数器的值,没用到不用管 TIM_TimeBaseStructure.TIM_RepetitionCounter = 0; // 初始化定时器 TIM_TimeBaseInit(GENERAL_TIM2, &TIM_TimeBaseStructure); // 清除计数器中断标志位 TIM_ClearFlag(GENERAL_TIM2, TIM_FLAG_Update); // 开启计数器中断 TIM_ITConfig(GENERAL_TIM2, TIM_IT_Update, ENABLE); // 使能计数器 TIM_Cmd(GENERAL_TIM2, DISABLE); } static void GENERAL_TIM3_NVIC_Config(void) { NVIC_InitTypeDef NVIC_InitStructure; // 设置中断组为0 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); // 设置中断来源 NVIC_InitStructure.NVIC_IRQChannel = GENERAL_TIM3_IRQ; // 设置主优先级为 0 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; // 设置抢占优先级为3 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); } static void GENERAL_TIM3_Mode_Config(void) { // 开启定时器时钟,即内部时钟CK_INT=8M GENERAL_TIM3_APBxClock_FUN(GENERAL_TIM3_CLK,ENABLE); TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; // 开启定时器时钟,即内部时钟CK_INT=8M GENERAL_TIM3_APBxClock_FUN(GENERAL_TIM3_CLK, ENABLE); // 自动重装载寄存器的值,累计TIM_Period+1个频率后产生一个更新或者中断 #ifdef SIMULATION TIM_TimeBaseStructure.TIM_Period = GENERAL_TIM3_Period + 1; #else TIM_TimeBaseStructure.TIM_Period = GENERAL_TIM3_Period; #endif // 时钟预分频数 TIM_TimeBaseStructure.TIM_Prescaler = GENERAL_TIM3_Prescaler; // 时钟分频因子 ,没用到不用管 TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; // 计数器计数模式,设置为向上计数 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // 重复计数器的值,没用到不用管 TIM_TimeBaseStructure.TIM_RepetitionCounter = 0; // 初始化定时器 TIM_TimeBaseInit(GENERAL_TIM3, &TIM_TimeBaseStructure); // 清除计数器中断标志位 TIM_ClearFlag(GENERAL_TIM3, TIM_FLAG_Update); // 开启计数器中断 TIM_ITConfig(GENERAL_TIM3, TIM_IT_Update, ENABLE); // 使能计数器 TIM_Cmd(GENERAL_TIM3, ENABLE); }

采用逐位扫描的方式识别按键,并使用软件消除抖动,即在查询到有键被按下后延时一段时间后再次查询这个按键。只有2次查询时按键都为有效状态才认为按键被按下。矩阵键盘模块的主要功能是进行分数的加减、默认初始时间的修改等,其中按键的主要功能为1键加1分,2键加2分,3键加3分,4键减1分,5键减2分,6键减3分。0键关闭蜂鸣器,*启动暂停计时器,#复位计时器,A选择A队,B键选择B队,C键初始状态下计时器加1分钟,D键计时器初始状态下减1分钟。

void KeyFunction(void) { char keyCode = 0; keyCode = KeyScan(); if (keyCode == ‘*’) { GENERAL_TIM2->CR1 ^= TIM_CR1_CEN; //启动/暂停计时 startFlag = 1; } else if (keyCode == ‘#’) //复位计时 { TIM_Cmd(GENERAL_TIM2, DISABLE); //停止计时 timeMinute = setTimeMinute; timeSecond = 0; time10ms = 0; roundNum = 1; scoreA = 0; scoreB = 0; startFlag = 0; } else if (keyCode == ‘A’)//切换A队 { teamFlag = 0; } else if (keyCode == ‘B’)//切换B队 { teamFlag = 1; } else if (keyCode == ‘C’)//计时器+1 { if (startFlag == 0) { if (timeMinute < 99) { timeMinute++; setTimeMinute++; } } } else if (keyCode == ‘D’)//计时器-1 { if (startFlag == 0) { if (timeMinute > 1) { timeMinute–; setTimeMinute–; } } } else if (keyCode == ‘0’) { BUZZER_OFF;//关闭蜂鸣器 } else if (keyCode == ‘1’) { if (teamFlag == 0) { scoreA++; } else { scoreB++; } } else if (keyCode == ‘2’) { if (teamFlag == 0) { scoreA += 2; } else { scoreB += 2; } } else if (keyCode == ‘3’) { if (teamFlag == 0) { scoreA += 3; } else { scoreB += 3; } } else if (keyCode == ‘4’) { if (teamFlag == 0) { if (scoreA > 0) { scoreA–; }

    }
    else
    {
        if (scoreB > 0)
        {
            scoreB--;
        }
    }
}
else if (keyCode == '5')
{
    if (teamFlag == 0)
    {
        if (scoreA >= 2)
        {
            scoreA -= 2;
        }
        
    }
    else
    {
        if (scoreB >= 2)
        {
            scoreB -= 2;
        }
    }
}
else if (keyCode == '6')
{
    if (teamFlag == 0)
    {
        if (scoreA >= 3)
        {
            scoreA -= 3;
        }
    }
    else
    {
        if (scoreB >= 3)
        {
            scoreB -= 3;
        }
    }
}

}

警报检测模块是通过判断定时器的时间来完成功能,当定时器的时间为0时,开启蜂鸣器和LED小灯。蜂鸣器通过一PNP三极管进行驱动,如图触发信号有基极引入。

if (timeMinute == 0) { timeMinute = setTimeMinute; timeSecond = 0; time10ms = 0; roundNum++; TIM_Cmd(GENERAL_TIM2, DISABLE); //停止计时 BUZZER_ON; if (roundNum > 4) roundNum = 1; }

3.5 LCD液晶显示驱动模块原理 void LCD_GPIO_Init(void) //GPIO初始化 void LCD_DispStr(uchar column, uchar row, char *p_str) //让液晶从某个位置起连续显示一个字符串 void LCD_DispNChar(uchar column, uchar row, uchar n, char *p_str)//让液晶从某个位置起连续显示N个字符 void LCD_DispOneChar(uchar column, uchar row, char dat) //在某个位置显示一个字符 void LCD_LocateXY(uchar column, uchar row) //向液晶输入显示字符位置的坐标信息 void LCD_Init() //对1602液晶模块进行复位操作 void LCD_WriteCommand(uchar cmd, uchar chk) //向液晶模块写入命令 void LCD_WriteData(uchar dat) //向液晶显示的当前地址写入显示数据 static void LCD_WaitForEnable(void) //等待1602液晶完成内部操作

//开始温度转换 void DS18B20_Start_Pin_4(void)// ds1820 start convert { DS18B20_Rst_Pin_4(); DS18B20_Check_Pin_4(); DS18B20_Write_Byte_Pin_4(0xcc);// skip rom DS18B20_Write_Byte_Pin_4(0x44);// convert } //初始化DS18B20的IO口 DQ 同时检测DS的存在 //返回1:不存在 //返回0:存在 u8 DS18B20_Init_Pin_4(void) { GPIO_InitTypeDef GPIO_InitStructure;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_4;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOB, &GPIO_InitStructure);

DS18B20_Rst_Pin_4();

return DS18B20_Check_Pin_4();

} //从ds18b20得到温度值 //精度:0.1C //返回值:温度值 (-550~1250) short DS18B20_Get_Temp_Pin(void) { u8 temp; u8 TL,TH; short tem;

DS18B20_Start_Pin_4 ();// ds1820 start convert
DS18B20_Rst_Pin_4();
DS18B20_Check_Pin_4();	 
DS18B20_Write_Byte_Pin_4(0xcc);// skip rom跳过rom
DS18B20_Write_Byte_Pin_4(0xbe);// convert	    
TL=DS18B20_Read_Byte_Pin_4(); // LSB   
TH=DS18B20_Read_Byte_Pin_4(); // MSB  高
if(TH>7)
{
    TH=~TH;
    TL=~TL; 
    temp=0;//温度为负  
}
else 
    temp=1;//温度为正
tem=TH; //获得高八位
tem<<=8;    
tem+=TL;//获得底八位
tem=(float)tem*0.625;//转换 

if(temp)
    return tem; //返回温度值
else 
    return -tem;    

}

4 运行效果展示 开启仿真,首先通过温度传感器获取温度,在液晶显示器上显示temp=24

调节温度传感器,改变温度大小

一段时间之后,LCD1602显示屏显示比赛计时计分界面 T:10:00:00 A 000–000 B

按下*键:LCD1602显示屏开始计时(比赛默认10分钟,可进行时间的调节)

按下*键:LCD1602显示屏计时暂停。

先按A键,选择A队,再按1,A队加1分:LCD1602显示屏 001–000

程序运行(按B键,选择B队,再按3,B队加3分):LCD1602显示屏 001–003

程序运行(按B键,选择B队,再按4,B队减1分):LCD1602显示屏 001–002

程序运行(按 # 键,进行复位操作):LCD1602显示屏 时间恢复为10:00:00 分数000–000

程序运行(按C键,比赛时间调整为11分钟):LCD1602显示屏 11:00:00 000–000

定时结束,蜂鸣器报警,LED小灯亮

按下0键,关闭蜂鸣器

5 总结

通过使用STM32F103R6芯片、LCD1602显示屏、矩阵键盘、蜂鸣器、LED小灯、温度传感器等原件,用proteus模拟仿真,实现了篮球比赛测温计时计分系统,实现了测量比赛环境温度、比赛倒计时和比分记录的操作。 主要收获:通过本次STM32的课程设计,我对定时器中断、AD转化、矩阵键盘等知识有了更深的认识。大二下学期学的51单片机,主要是编写程序,用编写的代码实现仿真,但是本学期学的STM32单片机,主要是调用函数,通过高电平与低电平的设置来调用对应函数,需要自己编写的程序相比51少了一些。之前学习51单边机的时候,我做的课程设计是定时器和简易计算器,使用的是数码管来进行显示,很少使用过本学期学习的DMA、串口通讯、AD转化等知识,所以在一开始学习STM32单边机这方面的知识时,就是做那几个实验的时候,也遇到了一些困难,从网上找了很多资源,才把问题逐渐解决。我把AD转化的知识也运用到了课程设计中,模拟环境温度并在LED液晶显示器进行显示,也学会了逐渐实现一些较为复杂的程序。充分的练习了单片机c语言的编程规则。相比于生活中的篮球比赛计分器,往往只能进行比赛分数与时间的控制,我进行了一些创新,将温度传感器加入进来,可以检测环境温度,使用户获得该温度是否适宜比赛等。 不足之处:本学期的学习中,我有许多不足之处,我在完成定时器功能的时候遇到了一些困难,程序的中断代码总是写不好,导致LED显示器有时候不能正常显示。在温度传感器获取环境温度时,总是获取不到数据,因而无法在LED显示器显示对应的温度。通过同学的帮助,也解决了这些问题,并实现了自己预期的效果。在以后的学习过程中,加深对STM32单片机的学习。

6 附录

Main.c #define __MAIN_C #include “main.h” #include “stm32f10x.h” #include “stm32f10x_gpio.h” #include “bsp_gpio.h” #include “bsp_clkconfig.h” #include “bsp_delay.h” #include “bsp_lcd1602.h” #include “bsp_GeneralTim.h” #include “bsp_keyArray.h” #include “stdio.h” #include “DS18B20.h”

CreatByte Flag; void display(int data); uint8_t roundNum = 1; uint8_t scoreA = 0; uint8_t scoreB = 0; volatile uint8_t timeMinute = 0; volatile uint8_t timeSecond = 0; volatile uint8_t time10ms = 0; uint8_t setTimeMinute = 10; int Temp=20;

int main(void) { char dis[16] = {0}; dispFlag = 1; startFlag = 0; teamFlag = 0; int Temp=20; int count=0; timeMinute = setTimeMinute; // 使用HSI,SYSCLK = 4M * RCC_PLLMul_x, x:[2,3,…16],最高是64MH HSI_SetSysClock(RCC_PLLMul_2); //使用内部8MHz晶振,并设置PLL输出为8MHz

// LED 端口初始化
GPIO_Config();
GENERAL_TIM_Init();
KeyArray_GPIO_Init();
LCD_GPIO_Init();//液晶显示器接口初始化
LCD_Init();
LCD_Clear();
DelayMs(250);
LCD_DispStr(0, 0, "    Welcome!    ");
DelayMs(500);
LCD_Clear();
  Temp=DS18B20_Get_Temp_Pin();
  DelayMs(750);
while(1)
	{
	Temp=DS18B20_Get_Temp_Pin();
  DelayMs(100);
	sprintf(dis, " Temp=%d%d", Temp%1000/100 ,Temp%1000%100/10 );
	LCD_DispStr(0, 1, dis);
		count++;
		if(count>20) break;
	}
	DelayMs(1500);
while (1)
{    	  
    if (dispFlag == 1)
    {
        dispFlag = 0;
        sprintf(dis, "R:%1d  T:%02d:%02d:%02d", (int)roundNum, (int)timeMinute, (int)timeSecond, (int)time10ms);//LCD液晶显示
        LCD_DispStr(0, 0, dis);
        DelayMs(10);
        if (teamFlag == 0)//显示A队得分或减分
        {
            sprintf(dis, ">A  %03d--%03d  B ", (int)scoreA, (int)scoreB);
            LCD_DispStr(0, 1, dis);
        }
        else//显示B队得分或减分
        {
            sprintf(dis, " A  %03d--%03d >B ", (int)scoreA, (int)scoreB);
            LCD_DispStr(0, 1, dis);
        }
    }
    KeyFunction();
}

}

bsp_GeneralTim.c #include “bsp_GeneralTim.h” // 中断优先级配置 static void GENERAL_TIM2_NVIC_Config(void) { NVIC_InitTypeDef NVIC_InitStructure; // 设置中断组为0 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); // 设置中断来源 NVIC_InitStructure.NVIC_IRQChannel = GENERAL_TIM2_IRQ; // 设置主优先级为 0 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; // 设置抢占优先级为3 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); }

static void GENERAL_TIM2_Mode_Config(void) { // 开启定时器时钟,即内部时钟CK_INT=8M GENERAL_TIM2_APBxClock_FUN(GENERAL_TIM2_CLK,ENABLE);

TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
// 开启定时器时钟,即内部时钟CK_INT=8M
GENERAL_TIM2_APBxClock_FUN(GENERAL_TIM2_CLK, ENABLE);
// 自动重装载寄存器的值,累计TIM_Period+1个频率后产生一个更新或者中断
#ifdef _SIMULATION_
TIM_TimeBaseStructure.TIM_Period = GENERAL_TIM2_Period + 1;
#else
TIM_TimeBaseStructure.TIM_Period = GENERAL_TIM2_Period;
#endif
// 时钟预分频数
TIM_TimeBaseStructure.TIM_Prescaler = GENERAL_TIM2_Prescaler;
// 时钟分频因子 ,没用到不用管
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
// 计数器计数模式,设置为向上计数
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
// 重复计数器的值,没用到不用管
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
// 初始化定时器
TIM_TimeBaseInit(GENERAL_TIM2, &TIM_TimeBaseStructure);

// 清除计数器中断标志位
TIM_ClearFlag(GENERAL_TIM2, TIM_FLAG_Update);

// 开启计数器中断
TIM_ITConfig(GENERAL_TIM2, TIM_IT_Update, ENABLE);

// 使能计数器
TIM_Cmd(GENERAL_TIM2, DISABLE);

}

// 中断优先级配置 static void GENERAL_TIM3_NVIC_Config(void) { NVIC_InitTypeDef NVIC_InitStructure; // 设置中断组为0 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); // 设置中断来源 NVIC_InitStructure.NVIC_IRQChannel = GENERAL_TIM3_IRQ; // 设置主优先级为 0 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; // 设置抢占优先级为3 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); }

static void GENERAL_TIM3_Mode_Config(void) { // 开启定时器时钟,即内部时钟CK_INT=8M GENERAL_TIM3_APBxClock_FUN(GENERAL_TIM3_CLK,ENABLE);

TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
// 开启定时器时钟,即内部时钟CK_INT=8M
GENERAL_TIM3_APBxClock_FUN(GENERAL_TIM3_CLK, ENABLE);
// 自动重装载寄存器的值,累计TIM_Period+1个频率后产生一个更新或者中断
#ifdef _SIMULATION_
TIM_TimeBaseStructure.TIM_Period = GENERAL_TIM3_Period + 1;
#else
TIM_TimeBaseStructure.TIM_Period = GENERAL_TIM3_Period;
#endif
// 时钟预分频数
TIM_TimeBaseStructure.TIM_Prescaler = GENERAL_TIM3_Prescaler;
// 时钟分频因子 ,没用到不用管
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
// 计数器计数模式,设置为向上计数
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
// 重复计数器的值,没用到不用管
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
// 初始化定时器
TIM_TimeBaseInit(GENERAL_TIM3, &TIM_TimeBaseStructure);

// 清除计数器中断标志位
TIM_ClearFlag(GENERAL_TIM3, TIM_FLAG_Update);

// 开启计数器中断
TIM_ITConfig(GENERAL_TIM3, TIM_IT_Update, ENABLE);

// 使能计数器
TIM_Cmd(GENERAL_TIM3, ENABLE);

}

void GENERAL_TIM_Init(void) { GENERAL_TIM2_NVIC_Config(); GENERAL_TIM2_Mode_Config();

GENERAL_TIM3_NVIC_Config();
GENERAL_TIM3_Mode_Config();

}

/***********************/

bsp_keyArray.c #include “bsp_keyArray.h” #include “bsp_GeneralTim.h” #include “stm32f10x.h” #include “main.h” #include “bsp_gpio.h”

#define KEY_ROW0_OUT_LOW (GPIO_ResetBits(KEY_ROW0_PORT, KEY_ROW0_PIN)) #define KEY_ROW0_OUT_HIGH (GPIO_SetBits (KEY_ROW0_PORT, KEY_ROW0_PIN))

#define KEY_ROW1_OUT_LOW (GPIO_ResetBits(KEY_ROW1_PORT, KEY_ROW1_PIN)) #define KEY_ROW1_OUT_HIGH (GPIO_SetBits (KEY_ROW1_PORT, KEY_ROW1_PIN))

#define KEY_ROW2_OUT_LOW (GPIO_ResetBits(KEY_ROW2_PORT, KEY_ROW2_PIN)) #define KEY_ROW2_OUT_HIGH (GPIO_SetBits (KEY_ROW2_PORT, KEY_ROW2_PIN))

#define KEY_ROW3_OUT_LOW (GPIO_ResetBits(KEY_ROW3_PORT, KEY_ROW3_PIN)) #define KEY_ROW3_OUT_HIGH (GPIO_SetBits (KEY_ROW3_PORT, KEY_ROW3_PIN))

volatile uint8_t KeyCol = 0xff; uint8_t keyCodeMap[16] = { //矩阵按键编号 ‘1’, ‘2’, ‘3’, ‘A’ , //数字键1、数字键2、数字键3、字母键A ‘4’, ‘5’, ‘6’, ‘B’ , //数字键4、数字键5、数字键6、字母键B ‘7’, ‘8’, ‘9’, ‘C’ , //数字键7、数字键8、数字键9、字母键C '', ‘0’, ‘#’, ‘D’ //字母键、数字键0、字母键#、字母键D };

void KeyArray_GPIO_Init(void)//键盘接口初始化 { GPIO_InitTypeDef GPIO_InitStructure;

GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE); //禁用jtag,不然写入程序和程序执行都会受影响
RCC_APB2PeriphClockCmd(KEY_COL_CLK, ENABLE);
RCC_APB2PeriphClockCmd(KEY_ROW_CLK, ENABLE);

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //设置引脚模式为通用推挽输出

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置引脚速率为50MHz

GPIO_InitStructure.GPIO_Pin = KEY_ROW_PINS;
GPIO_Init(KEY_COL_PORT, &GPIO_InitStructure);

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //设置引脚模式为内部上拉

GPIO_InitStructure.GPIO_Pin = KEY_COL_PINS;
GPIO_Init(KEY_ROW_PORT, &GPIO_InitStructure);

KEY_ROW0_OUT_HIGH;
KEY_ROW1_OUT_HIGH;
KEY_ROW2_OUT_HIGH;
KEY_ROW3_OUT_HIGH;

}

static uint8_t KeyColScan(void) { KeyCol = (uint8_t)GPIO_ReadInputData(KEY_COL_PORT); //矩阵键盘的列扫描 if (KeyCol != 0x0F) { DelayMs(5); if (KeyCol != 0x0F) { switch (KeyCol & 0x0F)//取低四位 { case 0x0E: //1110 判断为该列第1行的按键按下 return 1; case 0x0D: //1101 判断为该列第2行的按键按下 return 2; case 0x0B: //1011 判断为该列第3行的按键按下 return 3; case 0x07: //0111 判断为该列第4行的按键按下 return 4; default : return 0; } } else { return 0; } } else { return 0; } }

char KeyScan(void) { //矩阵键盘扫描 char keyNum = 0;//矩阵键盘的数值 char KeyColNum = 0;//矩阵行数

//低位有效 KEY_ROW0_OUT_LOW;//扫描第一行 KeyColNum = KeyColScan(); if ( KeyColNum != 0 ) { while(KeyColScan() != 0); keyNum = KeyColNum + 0;//第一行键盘 } KEY_ROW0_OUT_HIGH;//关闭第一行 KEY_ROW1_OUT_LOW;//扫描第二行 KeyColNum = KeyColScan(); if ( KeyColNum != 0 ) { while(KeyColScan() != 0); keyNum = KeyColNum + 4;//第二行键盘 } KEY_ROW1_OUT_HIGH;

KEY_ROW2_OUT_LOW;
KeyColNum = KeyColScan();
if ( KeyColNum != 0 )
{
    while(KeyColScan() != 0);
    keyNum = KeyColNum + 8;//第三行键盘
}
KEY_ROW2_OUT_HIGH;

KEY_ROW3_OUT_LOW;
KeyColNum = KeyColScan();
if ( KeyColNum != 0 )
{
    while(KeyColScan() != 0);
    keyNum = KeyColNum + 12;//第四行键盘
}
KEY_ROW3_OUT_HIGH;

if (keyNum == 0)
{
    return 0;
}
else
{
    return keyCodeMap[keyNum-1];
}

}

void KeyFunction(void) { char keyCode = 0;

keyCode = KeyScan();
if (keyCode == '*')
{
    GENERAL_TIM2->CR1 ^= TIM_CR1_CEN; //启动/暂停计时
    startFlag = 1;
}
else if (keyCode == '#') //复位计时
{
    TIM_Cmd(GENERAL_TIM2, DISABLE); //停止计时
    timeMinute = setTimeMinute;
    timeSecond = 0;
    time10ms = 0;
    roundNum = 1;   
    scoreA = 0;  
    scoreB = 0;  
    startFlag = 0;
}
else if (keyCode == 'A')//切换A队
{
    teamFlag = 0;
}
else if (keyCode == 'B')//切换B队
{
    teamFlag = 1;
}
else if (keyCode == 'C')//计时器+1
{
    if (startFlag == 0)
    {
        if (timeMinute < 99)
        {
            timeMinute++;
            setTimeMinute++;
        }
    }
}
else if (keyCode == 'D')//计时器-1
{
    if (startFlag == 0)
    {
        if (timeMinute > 1)
        {
            timeMinute--;
            setTimeMinute--;
        }
    }
}
else if (keyCode == '0')
{
    BUZZER_OFF;//关闭蜂鸣器
}
else if (keyCode == '1')
{
    if (teamFlag == 0)
    {
        scoreA++;
    }
    else
    {
        scoreB++;
    }
}
else if (keyCode == '2')
{
    if (teamFlag == 0)
    {
        scoreA += 2;
    }
    else
    {
        scoreB += 2;
    }
}
else if (keyCode == '3')
{
    if (teamFlag == 0)
    {
        scoreA += 3;
    }
    else
    {
        scoreB += 3;
    }
}
else if (keyCode == '4')
{
    if (teamFlag == 0)
    {
        if (scoreA > 0)
        {
            scoreA--;
        }
        
    }
    else
    {
        if (scoreB > 0)
        {
            scoreB--;
        }
    }
}
else if (keyCode == '5')
{
    if (teamFlag == 0)
    {
        if (scoreA >= 2)
        {
            scoreA -= 2;
        }
        
    }
    else
    {
        if (scoreB >= 2)
        {
            scoreB -= 2;
        }
    }
}
else if (keyCode == '6')
{
    if (teamFlag == 0)
    {
        if (scoreA >= 3)
        {
            scoreA -= 3;
        }
        
    }
    else
    {
        if (scoreB >= 3)
        {
            scoreB -= 3;
        }
    }
}

}

Bsp_gpio.c #include “bsp_gpio.h”

/**

  • @brief 初始化控制LED的IO

  • @param 无

  • @retval 无 */ void GPIO_Config(void) { /定义一个GPIO_InitTypeDef类型的结构体/ GPIO_InitTypeDef GPIO_InitStructure;

     /*开启LED相关的GPIO外设时钟*/
     RCC_APB2PeriphClockCmd( LED1_GPIO_CLK | LED2_GPIO_CLK | LED3_GPIO_CLK | LED4_GPIO_CLK | BUZZER_GPIO_CLK, ENABLE);	
    
     /*设置引脚模式为通用推挽输出*/
     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;   
    
     /*设置引脚速率为50MHz */   
     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 
    
     /*选择要控制的GPIO引脚*/
     GPIO_InitStructure.GPIO_Pin = LED1_GPIO_PIN;
    
     /*调用库函数,初始化GPIO*/
     GPIO_Init(LED1_GPIO_PORT, &GPIO_InitStructure);	
     
     /*选择要控制的GPIO引脚*/
     GPIO_InitStructure.GPIO_Pin = LED2_GPIO_PIN;
    
     /*调用库函数,初始化GPIO*/
     GPIO_Init(LED2_GPIO_PORT, &GPIO_InitStructure);
     
     /*选择要控制的GPIO引脚*/
     GPIO_InitStructure.GPIO_Pin = LED3_GPIO_PIN;
    
     /*调用库函数,初始化GPIOF*/
     GPIO_Init(LED3_GPIO_PORT, &GPIO_InitStructure);
     
     /*选择要控制的GPIO引脚*/
     GPIO_InitStructure.GPIO_Pin = LED4_GPIO_PIN;
    
     /*调用库函数,初始化GPIOF*/
     GPIO_Init(LED4_GPIO_PORT, &GPIO_InitStructure);
    
     /*选择要控制的GPIO引脚*/
     GPIO_InitStructure.GPIO_Pin = BUZZER_GPIO_PIN;
    
     /*调用库函数,初始化GPIOF*/
     GPIO_Init(BUZZER_GPIO_PORT, &GPIO_InitStructure);
    
     /* 关闭所有led灯	*/
     LED1_OFF;
     LED2_OFF;
     LED3_OFF;
     LED4_OFF;
     BUZZER_OFF;
    

} /***********************/ Bsp_lcd1602.c #include “bsp_lcd1602.h”

#define CLR_RS (GPIO_ResetBits(RS_GPIO_PORT, RS_GPIO_PIN)) #define SET_RS (GPIO_SetBits(RS_GPIO_PORT, RS_GPIO_PIN))

#if RW_PIN #define CLR_RW (GPIO_ResetBits(RW_GPIO_PORT, RW_GPIO_PIN)) #define SET_RW (GPIO_SetBits(RW_GPIO_PORT, RW_GPIO_PIN)) #endif

#define CLR_EN (GPIO_ResetBits(EN_GPIO_PORT, EN_GPIO_PIN)) #define SET_EN (GPIO_SetBits(EN_GPIO_PORT, EN_GPIO_PIN))

/**

  • @brief LCD1602_GPIO_Init

  • @param None

  • @retval None */ void LCD_GPIO_Init(void) { //GPIO初始化 GPIO_InitTypeDef GPIO_InitStructure;

    GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE); //禁用jtag,不然写入程序和程序执行都会受影响 RCC_APB2PeriphClockCmd(DQ_GPIO_CLK, ENABLE); RCC_APB2PeriphClockCmd(RS_GPIO_CLK | EN_GPIO_CLK, ENABLE); //打开GPIO时钟 #if RW_PIN RCC_APB2PeriphClockCmd(RW_GPIO_CLK, ENABLE); //打开GPIO时钟 #endif /设置引脚模式为通用推挽输出/ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

    /*设置引脚速率为50MHz */ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_InitStructure.GPIO_Pin = RS_GPIO_PIN; GPIO_Init(RS_GPIO_PORT, &GPIO_InitStructure);

    #if RW_PIN GPIO_InitStructure.GPIO_Pin = RW_GPIO_PIN; GPIO_Init(RW_GPIO_PORT, &GPIO_InitStructure); #endif

    GPIO_InitStructure.GPIO_Pin = EN_GPIO_PIN; GPIO_Init(EN_GPIO_PORT, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = DQ_GPIO_PIN; GPIO_Init(DQ_GPIO_PORT, &GPIO_InitStructure); }

/*********************************************** 函数名称:LCD_DispStr 功 能:让液晶从某个位置起连续显示一个字符串 参 数:column–位置的列坐标 row–位置的行坐标 p_str–指向字符串存放位置的指针 返回值 :无 ***********************************************/ void LCD_DispStr(uchar column, uchar row, char *p_str) { char *p_temp; uchar i; uchar n = 0;

p_temp = p_str;
while (*(p_str++) != '\0')
{
    n++; //计算字符串有效字符的个数
}
for (i = 0; i < n; i++)
{
    LCD_DispOneChar(column++, row, p_temp[i]);
    if (column == 0x10)
    {
        break;
    }
}

}

/******************************************* 函数名称:DispNchar 功 能:让液晶从某个位置起连续显示N个字符 参 数:column–位置的列坐标 row–位置的行坐标 n–字符个数 p_str–指向字符存放位置的指针 返回值 :无 ********************************************/ void LCD_DispNChar(uchar column, uchar row, uchar n, char *p_str) { uchar i;

for (i = 0; i < n; i++)
{
    LCD_DispOneChar(column++, row, p_str[i]);
    if (column == 0x10)
    {
        column = 0;
        row ^= 1;
    }
}

}

/******************************************* 函数名称:LCD_DispOneChar 功 能:在某个位置显示一个字符 参 数:column–位置的列坐标 row–位置的行坐标 data–显示的字符数据 返回值 :无 ********************************************/ void LCD_DispOneChar(uchar column, uchar row, char dat) { LCD_LocateXY(column, row); LCD_WriteData(dat); }

/******************************************* 函数名称:LCD_LocateXY 功 能:向液晶输入显示字符位置的坐标信息 参 数:column–位置的列坐标 row–位置的行坐标 返回值 :无 ********************************************/ void LCD_LocateXY(uchar column, uchar row) { uchar temp;

temp = column & 0x0f;
row &= 0x01;
if (row)
{
    temp |= 0x40; //如果在第2行
}
temp |= 0x80;

LCD_WriteCommand(temp, 0);

}

/******************************************* 函数名称:LCD_Init 功 能:对1602液晶模块进行复位操作 参 数:无 返回值 :无 ********************************************/ void LCD_Init() { //规定的复位操作 LCD_WriteCommand(0x38, 0); DelayMs(5); LCD_WriteCommand(0x38, 0); DelayMs(5); LCD_WriteCommand(0x38, 0); DelayMs(5);

LCD_WriteCommand(0x38, 1); //显示模式设置
LCD_WriteCommand(0x08, 1); //显示关闭
LCD_WriteCommand(0x01, 1); //显示清屏
LCD_WriteCommand(0x06, 1); //写字符时整体不移动
LCD_WriteCommand(0x0c, 1); //显示开,不开游标,不闪烁

}

/------------------------------------------------ 清屏函数 ------------------------------------------------/ void LCD_Clear() { LCD_WriteCommand(0x01, 0); DelayMs(5); }

/******************************************* 函数名称:LCD_SetCursor 功 能:让光标在某个位置闪烁 参 数:column–位置的列坐标 row–位置的行坐标 onFlag-- 1打开光标,0关闭光标 返回值 :无 ********************************************/ void LCD_SetCursor(uchar column, uchar row, uchar onFlag) { if (onFlag == 1) { LCD_WriteCommand(0x0F, 0); LCD_LocateXY(column, row); } }

/******************************************* 函数名称:LCD_WriteCommand 功 能:向液晶模块写入命令 参 数:cmd–命令, chk–是否判忙的标志,1:判忙,0:不判 返回值 :无 ********************************************/ void LCD_WriteCommand(uchar cmd, uchar chk) {

if (chk)
{
    LCD_WaitForEnable(); // 检测忙信号?
}

SET_EN;
CLR_RS;

#if _RW_PIN_
    CLR_RW;
#endif

DelayUs(200);

GPIO_Write(DQ_GPIO_PORT, (cmd | (GPIO_ReadOutputData(DQ_GPIO_PORT) & (~DQ_GPIO_PIN))));

SET_EN; //产生使能脉冲信号
DelayUs(200);
CLR_EN;

}

/******************************************* 函数名称:LCD_WriteData 功 能:向液晶显示的当前地址写入显示数据 参 数:dat–显示字符数据 返回值 :无 ********************************************/ void LCD_WriteData(uchar dat) { CLR_EN; SET_RS;

#if _RW_PIN_
    CLR_RW;
#endif

GPIO_Write(DQ_GPIO_PORT, (dat | (GPIO_ReadOutputData(DQ_GPIO_PORT) & (~DQ_GPIO_PIN))));

DelayUs(200);
SET_EN;
//产生使能脉冲信号
DelayUs(200);
CLR_EN;

}

/******************************************* 函数名称:LCD_WaitForEnable 功 能:等待1602液晶完成内部操作 参 数:无 返回值 :无 ********************************************/ static void LCD_WaitForEnable(void) { uint16_t later = 0; GPIO_InitTypeDef GPIO_InitStructure;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;	//第七Pin的工作方式为浮空输入模式,用于检测LCD1602的忙状态
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = DQ_GPIO_PIN;
GPIO_Init( DQ_GPIO_PORT, &GPIO_InitStructure );

CLR_RS;

#if _RW_PIN_
    SET_RW;
#endif

DelayUs(200);
SET_EN;
DelayUs(200);
//    while((DataIn&BUSY)!=0);
while (((GPIO_ReadInputDataBit( DQ_GPIO_PORT, DQ_GPIO_PIN) & BUSY) != 0) && (later < 1000)) //检测忙标志
{
    DelayUs(10);
    later++;
}
CLR_EN;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;	//使DQ_GPIO_PORT的状态还原成推挽模式
GPIO_Init( DQ_GPIO_PORT, &GPIO_InitStructure );

}

Delay.c

#include “bsp_delay.h” static uint32_t TimingDelay; void wait(__IO uint32_t n) { while (n–) ; } void DelayUs10x(__IO uint32_t nTime) { TimingDelay = nTime; //10us

if (SysTick_Config(SystemCoreClock / 100000)) //定时10us
{
    while (1)
        ;
}
while (TimingDelay != 0)   ;
// 关闭SysTick定时器
SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;

} void DelayMs(__IO uint16_t nTime) { TimingDelay = nTime; //1ms

if (SysTick_Config(SystemCoreClock / 1000)) //定时1ms
{
    while (1)
        ;
}
while (TimingDelay != 0)
    ;
// 关闭SysTick定时器
SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;

} void TimingDelay_Decrement(void) { if (TimingDelay != 0x00) { TimingDelay–; } } void SysTick_Handler(void) { TimingDelay_Decrement(); }

DS18B20 .c

#include <stm32f10x.h> #include “ds18b20.h” /*******************/

void Delay_DS18B20_1us(int num) { while(num–) ; }

void DS18B20_IO_OUT_Pin_4(void) { GPIO_InitTypeDef GPIO_InitStructure;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_4;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOB, &GPIO_InitStructure);    

}

void DS18B20_IO_IN_Pin_4(void) { GPIO_InitTypeDef GPIO_InitStructure;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_4;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOB, &GPIO_InitStructure);    

}

//复位DS18B20 void DS18B20_Rst_Pin_4(void) { DS18B20_IO_OUT_Pin_4(); //SET PA0 OUTPUT DS18B20_DQ_OUT_Pin_4(0); //拉低DQ Delay_DS18B20_1us(750); //拉低750us DS18B20_DQ_OUT_Pin_4(1); //DQ=1 Delay_DS18B20_1us(15); //15US } //等待DS18B20的回应 //返回1:未检测到DS18B20的存在 //返回0:存在 u8 DS18B20_Check_Pin_4(void) { u8 retry=0; DS18B20_IO_IN_Pin_4();//SET PA0 INPUT while (DS18B20_DQ_IN_Pin_4&&retry<200) { retry++; Delay_DS18B20_1us(1); }; if(retry>=200)return 1; else retry=0; while (!DS18B20_DQ_IN_Pin_4&&retry<240) { retry++; Delay_DS18B20_1us(1); }; if(retry>=240)return 1; return 0; } //从DS18B20读取一个位 //返回值:1/0 u8 DS18B20_Read_Bit_Pin_4(void) // read one bit { u8 data; DS18B20_IO_OUT_Pin_4();//SET PA0 OUTPUT DS18B20_DQ_OUT_Pin_4(0); Delay_DS18B20_1us(2); DS18B20_DQ_OUT_Pin_4(1); DS18B20_IO_IN_Pin_4();//SET PA0 INPUT Delay_DS18B20_1us(12); if(DS18B20_DQ_IN_Pin_4)data=1; else data=0; Delay_DS18B20_1us(50); return data; } //从DS18B20读取一个字节 //返回值:读到的数据 u8 DS18B20_Read_Byte_Pin_4(void) // read one byte { u8 i,j,dat; dat=0; for (i=1;i<=8;i++) { j=DS18B20_Read_Bit_Pin_4(); dat=(j<<7)|(dat>>1); } return dat; } //写一个字节到DS18B20 //dat:要写入的字节 void DS18B20_Write_Byte_Pin_4(u8 dat) { u8 j; u8 testb; DS18B20_IO_OUT_Pin_4();//SET PA0 OUTPUT; for (j=1;j<=8;j++) { testb=dat&0x01; dat=dat>>1; if (testb) { DS18B20_DQ_OUT_Pin_4(0);// Write 1 Delay_DS18B20_1us(2); DS18B20_DQ_OUT_Pin_4(1); Delay_DS18B20_1us(60); } else { DS18B20_DQ_OUT_Pin_4(0);// Write 0 Delay_DS18B20_1us(60); DS18B20_DQ_OUT_Pin_4(1); Delay_DS18B20_1us(2); } } } //开始温度转换 void DS18B20_Start_Pin_4(void)// ds1820 start convert { DS18B20_Rst_Pin_4(); DS18B20_Check_Pin_4(); DS18B20_Write_Byte_Pin_4(0xcc);// skip rom DS18B20_Write_Byte_Pin_4(0x44);// convert } //初始化DS18B20的IO口 DQ 同时检测DS的存在 //返回1:不存在 //返回0:存在 u8 DS18B20_Init_Pin_4(void) { GPIO_InitTypeDef GPIO_InitStructure;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_4;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOB, &GPIO_InitStructure);

DS18B20_Rst_Pin_4();

return DS18B20_Check_Pin_4();

} //从ds18b20得到温度值 //精度:0.1C //返回值:温度值 (-550~1250) short DS18B20_Get_Temp_Pin(void) { u8 temp; u8 TL,TH; short tem;

DS18B20_Start_Pin_4 ();                    // ds1820 start convert
DS18B20_Rst_Pin_4();
DS18B20_Check_Pin_4();	 
DS18B20_Write_Byte_Pin_4(0xcc);// skip rom跳过rom
DS18B20_Write_Byte_Pin_4(0xbe);// convert	    
TL=DS18B20_Read_Byte_Pin_4(); // LSB   
TH=DS18B20_Read_Byte_Pin_4(); // MSB  高
    	  
if(TH>7)
{
    TH=~TH;
    TL=~TL; 
    temp=0;//温度为负  
}
else 
    temp=1;//温度为正

tem=TH; //获得高八位
tem<<=8;    
tem+=TL;//获得底八位
tem=(float)tem*0.625;//转换 

if(temp)
    return tem; //返回温度值
else 
    return -tem;    

}

标签: 判断电阻大小内接外接6870c0442b倒屏电阻通用三极管pnp05n直流三线传感器ms类型晶体管bsp62三极管

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台