四、STM32练习题
1. 要求实现4个LED灯显示二进制的0-16,每次变幻时间为1s钟,LED灯接入的引脚是 PA5,PA6,PA7,PA8可能用到的函数和头文件如下 delay.h、led.h、Smg.h、Key.h、void Delayms(uint i)、void Delayus(uint a)、Void Led_Init(void)、void key_Init(void) 、void Smg_init()。
2. 要求实现通过按键控制LED灯闪烁、控制数码数码显示202107;实现效果如下:程序开始led灯和数码管保持熄灭,KEY1按键按下LED灯开始闪烁,KEY2按键按下显示202107并保持LED灯闪烁(本题运用的 I/O引脚有 PB1、PB2作为按键KEY1、KEY2;PA1作为LED灯;PC0-PC7作为数码管的断码,PA2-PA7作 为数码管的位码)。 需要注意的是本程序默认的是各硬件已经初始化完毕,初始化调用函数为:
void led_init(); //led初始化函数
void key_Init(); //按键初始化函数
void smg_Init(); //数码管初始化函数
另外可能会用到的函数为:
Delay(unsigned int count);
GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal);
3. 程序要求按键能控制LED灯的启停,LED灯流水8个分别是PA0-PA7,默认程序开始流水灯从PA0流 向PA7,当有按键按下时流水停止,当再次按下时流水灯再次开始流动,按键对应的端口为PB2。初始化的函数 void LED_Init() void Key_Init() void Delayms()
4. 请实现一个数码管显示通过按键key1每按键按下数码管显示内容加1按键key2按下一次显示内容加2 初始化函数自定义。
5. 请实现按键的多点击事件功能
按键key1按下一次点亮LED1再次按下一次熄灭LED1。
按键key1按下二次点亮LED2再次按下二次熄灭LED2。
按键key1按下三次同时点亮LED1,LED2再次按下三次熄灭LED1,LED2。
按键key1接在PA1 ,LED1接在PA2, LED2接在PA3;初始化函数自定义
6. 请使用定时器实现一个闹钟显示设计,显示内容为时分秒00:00:00通过按键key1,key2实现闹钟定时器时间设置,蜂鸣器实现闹钟声响,蜂鸣器接在PA1 按键key1接在PB1,按键key2接在PB2,初始化函数自定义。
7. 编程实现按键按下后,单片机读取温度传感器的数据并通过串口2发送到上位机,按键接PB0,低电平有效,温度传感器温度范围为-40到125度,当温度大于等于0时,发送温度数据前加上“+”字符,温度小于零时,温度数据前加上“-”字符,数据波特率为9600,程序IO、串口、获取温度由gpio_init()、uart2(9600)、get_tem()代替即可。
8. 编程实现一个时分秒的实时时钟,超过23:59:59后重新变成00:00:00.每秒钟通过串口2将时分秒的3个字节发送到上位机,程序中定时器,串口及定时器中断函数tim2_init(1),uart2(9600),tim2_interrupt()代替即可。
第一题
#include "stm32f10x.h"
#include "delay.h"
#include "led.h"
int i=0;
uint16_t arr[]={0xFFFF,0x1D0,0x1B0,0x190,0x170,0x150,0x130,0x110,0x0F0,0x0D0,0x0B0,0x090,0x070,0x050,0x030,0x010};
int main(void)
{
Led_Init();
while(1)
{
for(i=0;i<16;i++)
{
GPIO_Write(GPIOA,arr[i]);
Delayms(1000);
}
}
}
第二题
#include "stm32f10x.h"
#define KEY1 GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1)//获取按键接的引脚PB1的状态值,本题没有说明是高有效还是低有效,就默认为低有效,也就是当KEY1为0时,按键按下了
#define KEY2 GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_2)//获取按键接的引脚PB1的状态值,与上同理
int KEY1_Scan()//按键1的扫描函数
{
static int key1_val=0;//static表示key1_val只会在第一次调用的时候初始化为0,之后不再将它置为0
if(KEY1==0)//判断KEY1是否等于0,就是判断按键按下时
Delay(5);//延时5毫秒
if(KEY1==0)//若按键还为按下状态
key1_val=1;//让key_val等于1
return key1_val;//返回key_val的值
}
int KEY2_Scan()//与KEY1的扫描函数同理
{
static int key2_val=0;
if(KEY2==0)
Delay(5);
if(KEY2==0)
key2_val=1;
return key2_val;
}
int key1=0,key2=0,T_Count=0,i=0;
int duan[]={0x5b,0x3f,0x5b,0x06,0x3f,0x07};
int wei[]={0x7f,0xbf,0xdf,0xef,0xf7,0xfb};//本题位码接的引脚为PA2~PA7与书上不同,所以要自己算
//引脚PA2对应数码管第一位,将它置为0就表示,数码管第一位亮,以此类推。
int main(void)
{
led_init();
key_init();
smg_init();
while(1)
{
key1=KEY1_Scan();//将函数返回的值赋给key1
key2=KEY2_Scan();//将函数返回的值赋给key2
if(key1)//如果key1的值为真,也就是为1的时候,只有在KEY1按下了key1才会为1
{
if(T_Count<=200)//T_count在小于等于200时
GPIO_ResetBits(GPIOA,GPIO_Pin_1);//灯处于亮的状态,GPIO_ResetBits置0
else//否则就是T_count大于200时
GPIO_SetBits(GPIOA,GPIO_Pin_1);//灭灯
//本题涉及到数码管所以延时函数给的很小,(若延时函数给很大,就无法实现数码管的按键扫描),若用数码管的延时函数,灯的亮灭变化太快,肉眼不可见,所以使用T_count作为一个变量,在下面的Delay(5)每执行一次T_count加一次,在执行200次以前开灯,在200次以后灭灯,在T_count加到400后,将T_count置0,实现循环闪烁
}
if(key2)//当按键2按下
{
GPIO_Write(GPIOC,duan[i]);//断码
GPIO_Write(GPIOA,wei[i]);//位码
i++;//这个就是for循环中的i
if(i==6)i=0;//表示0~5,也就是数码管的第一位到第六位
}
Delay(5);//延时5毫秒
GPIO_Write(GPIOA,0xfc);//清空位码的显示
T_Count++;//作为LED灯闪烁的变量
if(T_Count>400) T_Count=0;//当加到400时,置为0,重新开始加
}
}
第三题
#include "stm32f10x.h"
#define KEY GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_2)
int KEY_Scan()
{
static int key_count=1;//1为开始,0为暂停
if(KEY==0)
Delayms(5);
if(KEY==0)
{
key_count=!key_count;
while(!KEY);
}
return key_count;
}
int key=0,count=0,temp=0xfe;
int mian(void)
{
LED_Init();
Key_Init();
while(1)
{
key=KEY_scan();
if(key)
{
GPIO_Write(GPIOA,temp);
count++;
temp=(temp<<1)+0x01;
if(count==8)
{
temp=0xfe;
count=0;
}
Delayms(10);
}
}
}
第四题
仿真图
#include "stm32f10x.h"
#define KEY1 GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_6)
#define KEY2 GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_7)
//PA0~PA7接断码,PB0~PB5接位码,PB6、PB7为按键KEY1和KEY2
void Delayms(int time)
{
int i,j;
for(i=0;i!=time;i++)
{
j=2000;
while(j--);
}
}
int i=0,key_val=0;
uint16_t wei[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf};
uint16_t duan[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
uint16_t display[]={0x3f,0x3f,0x3f,0x3f,0x3f,0x3f};
int KEY_scan(void)
{
static int count=0;
if(KEY1==0||KEY2==0)
{
if(KEY1==0)
Delayms(5);
if(KEY1==0)
{
count++;
while(!KEY1);
}
if(KEY2==0)
Delayms(5);
if(KEY2==0)
{
count+=2;
while(!KEY2);
}
}
return count;
}
int main(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin=0xB0;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin =0xff;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin=0x3f;
GPIO_Init(GPIOB, &GPIO_InitStructure);
while(1)
{
key_val=KEY_scan();
display[0]=duan[key_val%10];
display[1]=duan[key_val%100/10];
display[2]=duan[key_val%1000/100];
display[3]=duan[key_val%10000/1000];
display[4]=duan[key_val%100000/10000];
display[5]=duan[key_val%1000000/100000];
for(i=0;i<6;i++)
{
GPIO_Write(GPIOA,display[i]);
GPIO_Write(GPIOB,wei[i]);
Delayms(5);
GPIO_Write(GPIOB,0x3f);
}
}
}
第五题
仿真图
#include "stm32f10x.h"
#define KEY1 GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_1)
void Delayms(int time)
{
int i,j,t;
for(i=0;i!=time;i++)
{
for(j=0;j<20;j++)
{
t=100;
while(t--);
}
}
}
int KEY_scan(void)
{
static int count=0,temp=0,T_count=0;
if(KEY1==0)
{
count++;
while(!KEY1);
}
if(count)
T_count++;
if(T_count>=200)
{
temp=count;
count=0;
T_count=0;
return temp;
}
return 0;
}
int key_val=0;
int led1_count=1,led2_count=1,led3_count=1;
int main(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_1;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin =GPIO_Pin_2|GPIO_Pin_3;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_SetBits(GPIOA,GPIO_Pin_2|GPIO_Pin_3);
while(1)
{
Delayms(10);
key_val=KEY_scan();
switch(key_val)
{
case 1:if(led1_count) GPIO_ResetBits(GPIOA,GPIO_Pin_2);
else GPIO_SetBits(GPIOA,GPIO_Pin_2);
led1_count=!led1_count;
break;
case 2:if(led2_count) GPIO_ResetBits(GPIOA,GPIO_Pin_3);
else GPIO_SetBits(GPIOA,GPIO_Pin_3);
led2_count=!led2_count;
break;
case 3:if(led3_count) GPIO_ResetBits(GPIOA,GPIO_Pin_2|GPIO_Pin_3);
else GPIO_SetBits(GPIOA,GPIO_Pin_2|GPIO_Pin_3);
led3_count=!led3_count;
break;
}
}
}
第六题
仿真图
main.c
//以下为main.c
#include "gpio_init.h"
#include "timer.h"
#define KEY1 GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1)
#define KEY2 GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_2)
void Delay(unsigned int time);
uint16_t wei[]={0xfe0,0xfd0,0xfb0,0xf70,0xef0,0xdf0,0xbf0,0x7f0};
uint16_t duan[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
uint16_t display1[]={0x3f,0x3f,0x40,0x3f,0x3f,0x40,0x3f,0x3f};//正常的时间显示
uint16_t display2[8];//定时时的时间显示
int key2_val;//用于切换时、分、秒的加加,初始化为秒加加;KEY2按一下为分加加,再按KEY2一下为时加加,再按KEY2为秒加加,如此循环
int shi=0,fen=0,miao=0;//时分秒
int shi_count=0,fen_count=0,miao_count=0;//定时的时分秒
int i=0,j,flag=0;//i为数码管的for循环,j为判断是否到定时时间的for判断,flag为两个数组判断的中间量
int key_time=0;//用于无按键操作后3秒,恢复时间显示
int State_Pin_3=1;//判断Pin3的状态,用于控制KEY2关闭蜂鸣器
int main()
{
gpio_init();
TIM3_Init(999,71999);//一秒的定时
while(1)
{
if(KEY2==0)
{
if(State_Pin_3)//当蜂鸣器没有响的时候,为定时设置
{
key_time=3;
key2_val++;
if(key2_val==3) key2_val=0;
}
else//当蜂鸣器响时,为关闭蜂鸣器
{
State_Pin_3=1;
GPIO_SetBits(GPIOA,GPIO_Pin_1);
}
while(!KEY2);
}
if(KEY1==0)
{
key_time=3;
if(key2_val==0) miao_count++;
else if(key2_val==1) fen_count++;
else if(key2_val==2) shi_count++;
if(miao_count==60)
{
miao_count=0;
fen_count++;
if(fen_count==60)
{
shi_count++;
if(shi_count==24) shi_count=0;
}
}
while(!KEY1);
}
if(key_time)//正在定时操作
{
GPIO_ResetBits(GPIOA,GPIO_Pin_2);
display2[0]=duan[miao_count%10];
display2[1]=duan[miao_count/10];
display2[2]=0x40;
display2[3]=duan[fen_count%10];
display2[4]=duan[fen_count/10];
display2[5]=0x40;
display2[6]=duan[shi_count%10];
display2[7]=duan[shi_count/10];
for(i=0;i<8;i++)
{
GPIO_Write(GPIOC,display2[i]);
GPIO_Write(GPIOB,wei[i]);
Delay(10);
GPIO_Write(GPIOB,0xff0);
}
}
else//正常时间显示
{
GPIO_SetBits(GPIOA,GPIO_Pin_2);
display1[0]=duan[miao%10];
display1[1]=duan[miao/10];
display1[3]=duan[fen%10];
display1[4]=duan[fen/10];
display1[6]=duan[shi%10];
display1[7]=duan[shi/10];
miao_count=miao;
fen_count=fen;
shi_count=shi;
for(i=0;i<8;i++)
{
GPIO_Write(GPIOC,display1[i]);
GPIO_Write(GPIOB,wei[i]);
Delay(10);
GPIO_Write(GPIOB,0xff0);
}
for(j=0;j<8;j++)//判断是否到达定时时间
{
if(display1[j]==display2[j]) flag++;
else flag=0;
if(flag==8) //到达定时时间
{
State_Pin_3=0;
GPIO_ResetBits(GPIOA,GPIO_Pin_1);//蜂鸣器响
}
}
}
}
}
void Delay(unsigned int time)
{
int i,j;
for(i=0;i!=time;i++)
{
j=200;
while(j--);
}
}
timer.c
//以下为timer.c
#include "stm32f10x_tim.h"
#include "timer.h"
extern int miao,fen,shi,key_time;
void TIM3_Init(u16 arr,u16 psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值
TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据指定的参数初始化TIMx的时间基数单位
TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE ); //使能指定的TIM3中断,允许更新中断
//中断优先级NVIC设置
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; //TIM3中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //先占优先级0级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //从优先级3级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
NVIC_Init(&NVIC_InitStructure); //初始化NVIC寄存器
TIM_Cmd(TIM3, ENABLE); //使能TIMx
}
//定时器3中断服务程序
void TIM3_IRQHandler(void) //TIM3中断
{
miao++;
if(miao==60)
{
miao=0;
fen++;
if(fen==60)
{
fen=0;
shi++;
if(shi==24) shi=0;
}
}
if(key_time>0)
key_time--;
TIM_ClearITPendingBit(TIM3, TIM_IT_Update); //清除TIM3更新中断标志
}
//以下为gpio_init.c
#include "stm32f10x.h"
#include "gpio_init.h"
//按键、数码管、蜂鸣器初始化
void gpio_init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOC, ENABLE);
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
//按键初始化
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_1|GPIO_Pin_2;
GPIO_Init(GPIOB, &GPIO_InitStructure);
//蜂鸣器初始化
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin =GPIO_Pin_1;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_SetBits(GPIOA,GPIO_Pin_1);
//数码管初始化
GPIO_InitStructure.GPIO_Pin =0xff0;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin=0xff;
GPIO_Init(GPIOC, &GPIO_InitStructure);
}
第七题
#include "stm32f10x.h"
#define KEY GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_0)
void delay_ms(unsigned int time)
{
int i,t;
for(i=0;i!=time;i++)
{
t=2000;
while(t--);
}
}
int tem=0;
char arr[20];
int main(void)
{
gpio_init();
uart2(9600);
while(1)
{
if(KEY==0)
delay_ms(5);
if(KEY==0)
{
tem=get_tem();
if(tem>=0) arr[0]='+';
else arr[0]='-';
arr[1]=tem+'0';
sendbuffer(arr);
}
}
}
第九题
#include "stm32f10x.h"
#include "stm32f10x_tim.h"
int T_miao=0,T_fen=0,T_shi=0;
char arr[3];
void tim2_interrupt()
{
T_miao++;
TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
}
int main(void)
{
tim2_init(1);
uart2(9600);
while(1)
{
if(T_mian==60)
{
T_miao=0;
T_fen++;
if(T_fen==60)
{
T_fen=0;
T_shi++;
if(T_shi==24)
T_shi=0;
}
}
arr[0]=T_miao+'0';
arr[1]=T_fen+'0';
arr[2]=T_shi+'0';
sendbuffer(arr);
}
}
作者:刮大风了