当前位置: 首页 > news >正文

STM32F103C8T6 学习笔记摘要(三)

第一节 跑马灯实验

1. 了解电路

结构图

说明一下:

  •  那几个LED的引脚线和数码管的是一样的,如果不想让LED亮,就可以把J11的接线帽拔了
  • 这里的引脚是PA0-PA7

原理图 

说明一下:

  • 当J11接线帽盖上时,VCC3.3_LED就会有一个正电压
  • 而我们最终要实现跑马灯效果时,就是指定对应PA0-PA7的引脚上输入低电平,就可以了

 2. 初始化LED

Led.h 

#ifndef _H_LED
#define _H_LED
#include "stm32f10x.h"
#include "system.h"// 初始化LED
void led_init(void);#endif

 Led.c

#include "Led.h"// 封装点亮LED的前2步
void led_init(void)
{//step1: 给APB GPIOA 时钟使能RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//step2:将引脚的工作模式 设置为推挽输出50MHZGPIO_InitTypeDef initDef;initDef.GPIO_Speed = GPIO_Speed_50MHz;initDef.GPIO_Mode = GPIO_Mode_Out_PP;// PA0initDef.GPIO_Pin = GPIO_Pin_0;GPIO_Init(GPIOA,&initDef);GPIO_SetBits(GPIOA,GPIO_Pin_0);// 设置为高电平-对应LED不亮// PA1initDef.GPIO_Pin = GPIO_Pin_1;GPIO_Init(GPIOA,&initDef);GPIO_SetBits(GPIOA,GPIO_Pin_1);// 设置为高电平-对应LED不亮// PA2initDef.GPIO_Pin = GPIO_Pin_2;GPIO_Init(GPIOA,&initDef);GPIO_SetBits(GPIOA,GPIO_Pin_2);// 设置为高电平-对应LED不亮// PA3initDef.GPIO_Pin = GPIO_Pin_3;GPIO_Init(GPIOA,&initDef);GPIO_SetBits(GPIOA,GPIO_Pin_3);// 设置为高电平-对应LED不亮// PA4initDef.GPIO_Pin = GPIO_Pin_4;GPIO_Init(GPIOA,&initDef);GPIO_SetBits(GPIOA,GPIO_Pin_4);// 设置为高电平-对应LED不亮// PA5initDef.GPIO_Pin = GPIO_Pin_5;GPIO_Init(GPIOA,&initDef);GPIO_SetBits(GPIOA,GPIO_Pin_5);// 设置为高电平-对应LED不亮// PA6initDef.GPIO_Pin = GPIO_Pin_6;GPIO_Init(GPIOA,&initDef);GPIO_SetBits(GPIOA,GPIO_Pin_6);// 设置为高电平-对应LED不亮// PA7initDef.GPIO_Pin = GPIO_Pin_7;GPIO_Init(GPIOA,&initDef);GPIO_SetBits(GPIOA,GPIO_Pin_7);// 设置为高电平-对应LED不亮
}

 3. ledWriteData函数

 led.h

#ifndef _H_LED
#define _H_LED
#include "stm32f10x.h"
#include "system.h"// 初始化LED
void led_init(void);// 对应PA0-7设置为低电平 其他引脚为高电平
void ledWriteData(u8 data);#endif

 led.c

// 对应PA0-7设置为低电平 其他引脚为高电平
void ledWriteData(u8 data)
{// data=1111 1110(第1个led)for(u8 i = 0;i < 8;i++){if(data & 0x01){ // GPIO_WriteBit(GPIOA,GPIO_Pin_0<<i,Bit_SET);// 设置高电平}else{GPIO_WriteBit(GPIOA,GPIO_Pin_0<<i,Bit_RESET);// 设置低电平}data = data >> 1;// data = 0111 111(第8个led)}
}

 

 说明一下:

  • 首先GPIO_Pin_0 到GPIO_Pin_n的地址是有规律的,就是GPIO_Pin_n = GPIO_Pin_0 << n
    • GPIO_Pin_0<<i 表示GPIO_Pin_0 到GPIO_PIn_7

第一次循环:将第1个led设置为低电平

  • data & 0x01 表示1111 1110 & 0000 0001 = 0
    则进入:GPIO_WriteBit(GPIOA,GPIO_Pin_0<<i,Bit_RESET);// 设置低电平
  •  data = data >> 1;// data = 0111 111(第8个led)

 第二次循环:将第8个led设置为高电平

  • data & 0x01 表示0111 1111 & 0000 0001 = 1
    则进入:GPIO_WriteBit(GPIOA,GPIO_Pin_0<<i,Bit_SET);// 设置高电平
  •  data = data >> 1;// data = 1011 1111(第7个led)

依次类推,第7个 第6个led都将设置为高电平

4. main函数

#include "stm32f10x.h"
#include "Led.h"
#include "systick.h"
int main()
{SysTick_Init(72);//1.初始化ledled_init();u8 i = 0;while(1){// 设置第1个为低电平 其他为高电平ledWriteData(~(0x01<<i));i++;if(i>7){i=0;}// 定时delay_ms(100);}//return 0;
}

第二节 蜂鸣器实验

1. 了解电路

结构图

原理图 

2. beep.h

#ifndef _H_BEEP
#define _H_BEEP
#include "stm32f10x.h"
#include "system.h"
#include "systick.h"// 位带操作-PB0
#define BEEP PBout(0)// 初始化LED
void beep_init(void);// time持续时间 us延迟时间
void beep_active(u16 time,u8 us);#endif

说明一下:

  • #define BEEP PBout(0),这里使用了位带操作,方便后面将其设置为低电平 

3. beep.c

#include "beep.h"// 初始化LED
void beep_init(void)
{// PB0// 开启时钟始能RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);// 设置工作模式GPIO_InitTypeDef initdef;initdef.GPIO_Speed = GPIO_Speed_50MHz;initdef.GPIO_Pin = GPIO_Pin_0;initdef.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_Init(GPIOB,&initdef);// 设置为高电平GPIO_SetBits(GPIOB,GPIO_Pin_0);}// time持续时间 us延迟时间
void beep_active(u16 time,u8 us)
{while(time--){BEEP=!BEEP;delay_us(us);}
}

4. main.c

#include "stm32f10x.h"
#include "beep.h"
#include "systick.h"int main()
{SysTick_Init(72);// 1. 初始化蜂鸣器beep_init();while(1){// 2. 活跃蜂鸣器beep_active(100,100);delay_ms(200);}
}

第三节 数码管实验

1. 数码管简介

        数码管是一种半导体发光器件,其基本单元是发光二极管。数码管也称LED数码管,不同行业人士对数码管的称呼不一样,其实都是同样的产品。数码管按段数可分为七段数码管和八段数码管,八段数码管比七段数码管多一个发光二极管单元,也就是多一个小数点(DP),这个小数点可以更精确的表示数码管想要显示的内容;按能显示多少个(8)可分为 1 位、 2 位、3 位、4 位、5位、6 位、7 位等数码管。按发光二极管单元连接方式可分为共阳极数码管共阴极数码管

2. 数码管显示原理

共阴极时,高电平,亮,而共阳极反之

 

         从上图可看出,一位数码管的引脚是 10 个,显示一个8 字需要7 个小段,另外还有一个小数点,所以其内部一共有 8 个小的发光二极管,最后还有一个公共端,多数生产商为了封装统一,单位数码管都封装10 个引脚,其中第3和第 8 引脚是连接在一起的。而它们的公共端又可分为共阳极和共阴极,图中间为共阳极内部原理图,右图为共阴极内部原理图。  

3. 了解电路

结构图

原理图 

 

说明一下:

  • 对于PB3 PB4 PB5 来说需要关闭调试,才能当做基础的GPIO口使用

4. 关于74HC245芯片

芯片74HC245 是一种三态输出、八路信号收发器,主要应用于大屏显示,以及其它的消费类电子产品中增加驱动。

5. 简单总结

  • 位选三条线(LSA、LSB、LSC)PB5、4、3 
  • 段选8条线 PA0 - PA7

6. smg.h

#ifndef _H_SMG
#define _H_SMG
#include "stm32f10x.h"
#include "system.h"
#define LSA PBout(5)
#define LSB PBout(4)
#define LSC PBout(3)// 初始化smg
void smg_init(void);// 设置低电平
void smgWriteData(u8 data);#endif

7. smg.c

smg_init函数

void smg_init(void)
{//1.给APB2 GPIOA GPIOB 时钟使能RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);// 关闭PB3 PB4 PB5调试,使其能当作正常GPIO口使用RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);GPIO_PinRemapConfig(GPIO_Remap_SWJ_Disable,ENABLE);//2. 设置工作模式GPIO_InitTypeDef initDef;initDef.GPIO_Speed= GPIO_Speed_50MHz;initDef.GPIO_Mode = GPIO_Mode_Out_PP;//PA0-PA7initDef.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5  | GPIO_Pin_6 | GPIO_Pin_7;GPIO_Init(GPIOA,&initDef);	//PB3-PB5initDef.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_4 | GPIO_Pin_3;GPIO_Init(GPIOB,&initDef);
}	

 smgWriteData函数

void smgWriteData(u8 data)
{// data=1111 1110(第1个led)for(u8 i = 0;i < 8;i++){if(data & 0x01){ // GPIO_WriteBit(GPIOA,GPIO_Pin_0<<i,Bit_SET);// 设置高电平}else{GPIO_WriteBit(GPIOA,GPIO_Pin_0<<i,Bit_RESET);// 设置低电平}data = data >> 1;// data = 0111 111(第8个led)}
}

8. main.c

#include "stm32f10x.h"
#include "smg.h"
#include "systick.h"u8 gsmg_code[17] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};int main()
{SysTick_Init(72);// 1. 初始化蜂鸣器smg_init();while(1){// 在那个位置上显示 - 位选LSC = 0;LSB = 0;LSA = 1;// 在对应的位置上显示什么内容 - 段选for(u8 i = 0;i < 10;i++){	smgWriteData(gsmg_code[i]);delay_ms(1000);}}
}

第四节 独立按键实验-默认是高电平

    按键是一种电子开关,使用时轻轻按开关按钮就可使开关接通,当松开手时,开关断开。我们开发板上使用的按键及内部简易图如下图所示

         按键管脚两端距离长的表示默认是导通状态,距离短的默认是断开状态,如果按键按下,初始导通状态变为断开,初始断开状态变为导通。通常的按键所用开关为机械弹性开关,当机械触点断开、闭合时,电压信号如下图所示:

        由于机械点的弹性作用,按键开关在闭合时不会马上稳定的接通,在断开时也不会一下子断开,因而在闭合和断开的瞬间均伴随着一连串的抖动。抖动时间的长短由按键的机械特性决定的,一般为 5ms 到 10ms。按键稳定闭合时间的长短则由操作人员的按键动作决定的,一般为零点几秒至数秒。按键抖动会引起按键被误读多次。为了确保 CPU 对按键的一次闭合仅作一次处理,必须进行消抖。  

        按键消抖有两种方式,一种是硬件消抖,另一种是软件消抖。为了使电路更加简单,通常采用软件消抖。我们开发板也是采用软件消抖,一般来说一个简单的按键消抖就是先读取按键的状态如果得到按键按下之后,延时10ms,再次读取按键的状态如果按键还是按下状态,那么说明按键已经按下。其中延时10ms 就是软件消抖处理至于硬件消抖,大家可以百度了解下,网上都有非常详细的介绍

1. 了解电路

结构图 

原理图 

说明一下:

  • 默认是高电平,按下按钮之后才能变成低电平

2. key初始化

        这个板子上有4个按键,我想让它控制对应的led0 led1 led2 led3 led4

key.h

#ifndef _H_KEY
#define _H_KEY
#include "stm32f10x.h"
#include "system.h"
#include "systick.h"// 位带操作
#define KEY1 PAin(15)
#define KEY2 PAin(14)
#define KEY3 PAin(13)
#define KEY4 PAin(12)// 初始化按键
void key_init(void);// 检查按键状态
u8 keyScan(u8 mode);#endif

 key_init函数

#include "key.h"// 初始化按键
void key_init(void){// 1gpio时钟使能RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); //使能是GPIOARCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);	// 使能 AFIO 时钟// 这几根线上也有调试功能GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);// 关闭JTAG 和 SWD 功能GPIO_PinRemapConfig(GPIO_Remap_SWJ_Disable, ENABLE);	// 关闭JTAG 和 SWD 功能// 设置工作模式GPIO_InitTypeDef initDef;initDef.GPIO_Mode = GPIO_Mode_IPU;// 上拉输入模式initDef.GPIO_Speed = GPIO_Speed_50MHz;initDef.GPIO_Pin = GPIO_Pin_12;GPIO_Init(GPIOA,&initDef);initDef.GPIO_Pin = GPIO_Pin_13;GPIO_Init(GPIOA,&initDef);initDef.GPIO_Pin = GPIO_Pin_14;GPIO_Init(GPIOA,&initDef);initDef.GPIO_Pin = GPIO_Pin_15;GPIO_Init(GPIOA,&initDef);
}

 说明一下:

  • PA12-PA15这几根线上也有调式功能,初始化时需要关闭
  • 注意:它的工作模式应该设置为上拉输入

led.h 

3. key.c

#include "key.h"// 初始化按键
void key_init(void){// 1gpio时钟使能RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); //使能是GPIOARCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);	// 使能 AFIO 时钟// 这几根线上也有调试功能GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);// 关闭JTAG 和 SWD 功能GPIO_PinRemapConfig(GPIO_Remap_SWJ_Disable, ENABLE);	// 关闭JTAG 和 SWD 功能// 设置工作模式GPIO_InitTypeDef initDef;initDef.GPIO_Mode = GPIO_Mode_IPU;// 上拉输入模式initDef.GPIO_Speed = GPIO_Speed_50MHz;initDef.GPIO_Pin = GPIO_Pin_12;GPIO_Init(GPIOA,&initDef);initDef.GPIO_Pin = GPIO_Pin_13;GPIO_Init(GPIOA,&initDef);initDef.GPIO_Pin = GPIO_Pin_14;GPIO_Init(GPIOA,&initDef);initDef.GPIO_Pin = GPIO_Pin_15;GPIO_Init(GPIOA,&initDef);
}// 检查按键状态
u8 keyScan(u8 mode)
{static u8 flag = 1;if(mode) flag = 1;// 持续检测-长按按键出现闪烁效果if(flag && (KEY1 == 0 ||KEY2 == 0 || KEY3 == 0 || KEY4 == 0))	{delay_ms(10);// 消抖flag = 0;// 返回值:表示确定是那个按键被按下,切换对应的LED状态if(KEY1 == 0) return 1;if(KEY2 == 0) return 2;if(KEY3 == 0) return 3;if(KEY4 == 0) return 4;}// 此时所有按键都没有被按下else if(KEY1 == 1 && KEY2 == 1 && KEY3 == 1 && KEY4 == 1){flag = 1;}else{return 0;}
}

 说明一下

  • mode = 1表示长按按键时出现闪烁效果
  • mode = 0表示长按按键出现常亮效果

4. main.c 

#include "stm32f10x.h"
#include "led.h"
#include "key.h"
#include "systick.h"int main()
{// 滴答定时器SysTick_Init(72);// 初始化led_init();key_init();u8 i = 0;while(1){i = keyScan(0);if(i == 1) LED1 = !LED1;else if(i == 2) LED2 = !LED2;else if(i == 3) LED3 = !LED3;else if(i == 4) LED4 = !LED4;delay_ms(150);}
}

第五节. 矩阵按键实验

1. 了解电路

结构图

说明一下:

  • 我们要做的是让前2排按键点亮led1-led8
  • 后两排要做的是点灭led1-led8 

原理图

2. key.h

我们要做的是让前2排按键点亮led1-led8后两排要做的是点灭led1-led8 

Led.h 

key.h 

#ifndef _H_KEY
#define _H_KEY
#include "stm32f10x.h"
#include "system.h"
#include "systick.h"// 四根行线
#define KEY_H1_PIN GPIO_Pin_8
#define KEY_H2_PIN GPIO_Pin_9
#define KEY_H3_PIN GPIO_Pin_10
#define KEY_H4_PIN GPIO_Pin_11// 四根列线
#define KEY_L1_PIN GPIO_Pin_12
#define KEY_L2_PIN GPIO_Pin_13
#define KEY_L3_PIN GPIO_Pin_14
#define KEY_L4_PIN GPIO_Pin_15// 初始化按键
void key_init(void);// 检查按键状态
u8 keyScan(void);#endif

3. key_init函数

#include "key.h"// 初始化按键
void key_init(void){// 1gpio时钟使能RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); //使能是GPIOARCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);	// 使能 AFIO 时钟// 这几根线上也有调试功能GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);// 关闭JTAG 和 SWD 功能GPIO_PinRemapConfig(GPIO_Remap_SWJ_Disable, ENABLE);	// 关闭JTAG 和 SWD 功能// 四根行线设置为下拉输入 - 设置工作模式GPIO_InitTypeDef initDef;initDef.GPIO_Speed = GPIO_Speed_50MHz;initDef.GPIO_Mode = GPIO_Mode_IPD;// 下拉输入模式initDef.GPIO_Pin = GPIO_Pin_12;GPIO_Init(GPIOB,&initDef);initDef.GPIO_Pin = GPIO_Pin_13;GPIO_Init(GPIOB,&initDef);initDef.GPIO_Pin = GPIO_Pin_14;GPIO_Init(GPIOB,&initDef);initDef.GPIO_Pin = GPIO_Pin_15;GPIO_Init(GPIOB,&initDef);// 四根列线设置为推挽输出 - 设置工作模式initDef.GPIO_Mode = GPIO_Mode_Out_PP;// 推挽输出模式initDef.GPIO_Pin = GPIO_Pin_8;GPIO_Init(GPIOB,&initDef);initDef.GPIO_Pin = GPIO_Pin_9;GPIO_Init(GPIOB,&initDef);initDef.GPIO_Pin = GPIO_Pin_10;GPIO_Init(GPIOB,&initDef);initDef.GPIO_Pin = GPIO_Pin_11;GPIO_Init(GPIOB,&initDef);}

说明一下:

  • 四根行线设置为下拉输入 - 设置工作模式
  • 四根列线设置为推挽输出 - 设置工作模式

4. keyScan函数(有bug)

GPIO_ReadInputDataBit - 读取指定端口管脚的输入

keyScan函数 

// 检查按键状态
u8 keyScan()
{// 设置前四行为高电平GPIO_SetBits(GPIOB,KEY_H1_PIN);GPIO_SetBits(GPIOB,KEY_H2_PIN);GPIO_SetBits(GPIOB,KEY_H3_PIN);GPIO_SetBits(GPIOB,KEY_H4_PIN);// 读取指定端口管脚的输入if((GPIO_ReadInputDataBit(GPIOB,KEY_L1_PIN)) | (GPIO_ReadInputDataBit(GPIOB,KEY_L2_PIN))| (GPIO_ReadInputDataBit(GPIOB,KEY_L3_PIN))| (GPIO_ReadInputDataBit(GPIOB,KEY_L4_PIN)) == 0){// 没有按键被按下return 0;}else{// 等待一会儿 再读取// 读取指定端口管脚的输入if((GPIO_ReadInputDataBit(GPIOB,KEY_L1_PIN)) | (GPIO_ReadInputDataBit(GPIOB,KEY_L2_PIN))| (GPIO_ReadInputDataBit(GPIOB,KEY_L3_PIN))| (GPIO_ReadInputDataBit(GPIOB,KEY_L4_PIN)) == 0){// 没有按键被按下return 0;}}}

 keyScan函数 

// 检查按键状态
u8 keyScan()
{// 设置前四行为高电平GPIO_SetBits(GPIOB,KEY_H1_PIN);GPIO_SetBits(GPIOB,KEY_H2_PIN);GPIO_SetBits(GPIOB,KEY_H3_PIN);GPIO_SetBits(GPIOB,KEY_H4_PIN);// 读取指定端口管脚的输入if((GPIO_ReadInputDataBit(GPIOB,KEY_L1_PIN)) | (GPIO_ReadInputDataBit(GPIOB,KEY_L2_PIN))| (GPIO_ReadInputDataBit(GPIOB,KEY_L3_PIN))| (GPIO_ReadInputDataBit(GPIOB,KEY_L4_PIN)) == 0){// 没有按键被按下return 0;}else{// 等待一会儿 再读取// 读取指定端口管脚的输入if((GPIO_ReadInputDataBit(GPIOB,KEY_L1_PIN)) | (GPIO_ReadInputDataBit(GPIOB,KEY_L2_PIN))| (GPIO_ReadInputDataBit(GPIOB,KEY_L3_PIN))| (GPIO_ReadInputDataBit(GPIOB,KEY_L4_PIN)) == 0){// 没有按键被按下return 0;}}// 检测是否有按键被按下u8 col1,col2,col3,col4;// 第一行:设置第一行为低电平 其他为高电平GPIO_SetBits(GPIOB,KEY_H1_PIN);GPIO_ResetBits(GPIOB,KEY_H2_PIN);GPIO_ResetBits(GPIOB,KEY_H3_PIN);GPIO_ResetBits(GPIOB,KEY_H4_PIN);// 读取四列的状态	col1 = GPIO_ReadInputDataBit(GPIOB,KEY_L1_PIN);col2 = GPIO_ReadInputDataBit(GPIOB,KEY_L2_PIN);col3 = GPIO_ReadInputDataBit(GPIOB,KEY_L3_PIN);col4 = GPIO_ReadInputDataBit(GPIOB,KEY_L4_PIN);if(col1 == 1 && col2 == 0&& col3==0 && col4 == 0) return 1;if(col1 == 0 && col2 == 1&& col3==0 && col4 == 0) return 2;if(col1 == 0 && col2 == 0&& col3==1 && col4 == 0) return 3;if(col1 == 0 && col2 == 0&& col3==0 && col4 == 1) return 4;while((GPIO_ReadInputDataBit(GPIOB,KEY_L1_PIN)) | (GPIO_ReadInputDataBit(GPIOB,KEY_L2_PIN))| (GPIO_ReadInputDataBit(GPIOB,KEY_L3_PIN))| (GPIO_ReadInputDataBit(GPIOB,KEY_L4_PIN)) > 0);// 第二行:设置第二行为低电平 其他为高电平GPIO_ResetBits(GPIOB,KEY_H1_PIN);GPIO_SetBits(GPIOB,KEY_H2_PIN);GPIO_ResetBits(GPIOB,KEY_H3_PIN);GPIO_ResetBits(GPIOB,KEY_H4_PIN);// 读取四列的状态	col1 = GPIO_ReadInputDataBit(GPIOB,KEY_L1_PIN);col2 = GPIO_ReadInputDataBit(GPIOB,KEY_L2_PIN);col3 = GPIO_ReadInputDataBit(GPIOB,KEY_L3_PIN);col4 = GPIO_ReadInputDataBit(GPIOB,KEY_L4_PIN);if(col1 == 1 && col2 == 0&& col3==0 && col4 == 0) return 5;if(col1 == 0 && col2 == 1&& col3==0 && col4 == 0) return 6;if(col1 == 0 && col2 == 0&& col3==1 && col4 == 0) return 7;if(col1 == 0 && col2 == 0&& col3==0 && col4 == 1) return 8;while((GPIO_ReadInputDataBit(GPIOB,KEY_L1_PIN)) | (GPIO_ReadInputDataBit(GPIOB,KEY_L2_PIN))| (GPIO_ReadInputDataBit(GPIOB,KEY_L3_PIN))| (GPIO_ReadInputDataBit(GPIOB,KEY_L4_PIN)) > 0);// 第三行:设置第三行为低电平 其他为高电平GPIO_ResetBits(GPIOB,KEY_H1_PIN);GPIO_ResetBits(GPIOB,KEY_H2_PIN);GPIO_SetBits(GPIOB,KEY_H3_PIN);GPIO_ResetBits(GPIOB,KEY_H4_PIN);// 读取四列的状态	col1 = GPIO_ReadInputDataBit(GPIOB,KEY_L1_PIN);col2 = GPIO_ReadInputDataBit(GPIOB,KEY_L2_PIN);col3 = GPIO_ReadInputDataBit(GPIOB,KEY_L3_PIN);col4 = GPIO_ReadInputDataBit(GPIOB,KEY_L4_PIN);if(col1 == 1 && col2 == 0&& col3==0 && col4 == 0) return 9;if(col1 == 0 && col2 == 1&& col3==0 && col4 == 0) return 10;if(col1 == 0 && col2 == 0&& col3==1 && col4 == 0) return 11;if(col1 == 0 && col2 == 0&& col3==0 && col4 == 1) return 12;while((GPIO_ReadInputDataBit(GPIOB,KEY_L1_PIN)) | (GPIO_ReadInputDataBit(GPIOB,KEY_L2_PIN))| (GPIO_ReadInputDataBit(GPIOB,KEY_L3_PIN))| (GPIO_ReadInputDataBit(GPIOB,KEY_L4_PIN)) > 0);// 第四行:设置第四行为低电平 其他为高电平GPIO_ResetBits(GPIOB,KEY_H1_PIN);GPIO_ResetBits(GPIOB,KEY_H2_PIN);GPIO_ResetBits(GPIOB,KEY_H3_PIN);GPIO_SetBits(GPIOB,KEY_H4_PIN);// 读取四列的状态	col1 = GPIO_ReadInputDataBit(GPIOB,KEY_L1_PIN);col2 = GPIO_ReadInputDataBit(GPIOB,KEY_L2_PIN);col3 = GPIO_ReadInputDataBit(GPIOB,KEY_L3_PIN);col4 = GPIO_ReadInputDataBit(GPIOB,KEY_L4_PIN);if(col1 == 1 && col2 == 0&& col3==0 && col4 == 0) return 13;if(col1 == 0 && col2 == 1&& col3==0 && col4 == 0) return 14;if(col1 == 0 && col2 == 0&& col3==1 && col4 == 0) return 15;if(col1 == 0 && col2 == 0&& col3==0 && col4 == 1) return 16;while((GPIO_ReadInputDataBit(GPIOB,KEY_L1_PIN)) | (GPIO_ReadInputDataBit(GPIOB,KEY_L2_PIN))| (GPIO_ReadInputDataBit(GPIOB,KEY_L3_PIN))| (GPIO_ReadInputDataBit(GPIOB,KEY_L4_PIN)) > 0);return 0;}

5. main.c

#include "stm32f10x.h"
#include "led.h"
#include "key.h"
#include "systick.h"int main()
{// 滴答定时器SysTick_Init(72);// 初始化led_init();key_init();u8 i = 0;while(1){i = keyScan();// 前2排按键按下 点亮LEDif(i == 1) LED1 = 0;else if(i == 2) LED2 = 0;else if(i == 3) LED3 = 0;else if(i == 4) LED4 = 0;else if(i == 5) LED5 = 0;else if(i == 6) LED6 = 0;else if(i == 7) LED7 = 0;else if(i == 8) LED8 = 0;// 后2排按键按下 点灭LEDelse if(i == 9) LED1 = 1;else if(i == 10) LED2 = 1;else if(i == 11) LED3 = 1;else if(i == 12) LED4 = 1;else if(i == 13) LED5 = 1;else if(i == 14) LED6 = 1;else if(i == 15) LED7 = 1;else if(i == 16) LED8 = 1;delay_ms(150);}
}

第六节 点阵实验

1. 了解电路

结构图

原理图 

说明一下:

  • 当需要串联其他点阵时,就需要使用VCC3.39号线 

2. 74HC595芯片介绍

点阵 LED 基本结构 

  • 右侧(ROW1-ROW8) 控制的是行(阳极/正极)。

  • 下侧(SMG A ~ SMG DP) 控制的是列(阴极/负极)

 74HC595 是一个 8 位串行转并行移位寄存器,它的作用是:

  •  将你通过 SER 引脚串行输入的 8 位数据,在 SRCLK(移位时钟)作用下依次移入。
  • 当你触发 RCLK(锁存时钟)的 上升沿 时,数据会被输出到 QA~QH(即点阵的行控制)。

点阵工作流程(动态扫描)  

 

  • 只有设置为高电平有效 只有设置为低电平有效 则我们点亮第 1 行第 1 列的 LED(即 A1-K1 对应 LED):
  • 行为0x08 列为0x7F

关键信号控制如下: 

 

工作原理 

  • 采用高位的输入 数据到 移位寄存器中 

3. dzled.h

#ifndef _H_DZLED
#define _H_DZLED
#include "stm32f10x.h"
#include "system.h"
#include "systick.h"// 三个总要信号 - 产生上升沿
#define SER PBout(4)
#define RCLK PBout(5)
#define SRCLK PBout(3)// 初始化点阵
void dzled_init(void);// 行输入
void writeRowData(u8 data);// 列输入
void writeColData(u8 data);#endif

4. dzled.c 

 dzled_init函数

// 初始化点阵
void dzled_init(void)
{//1.给APB2 GPIOA GPIOB 时钟使能RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);// 关闭PB3 PB4 PB5调试,使其能当作正常GPIO口使用RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);GPIO_PinRemapConfig(GPIO_Remap_SWJ_Disable,ENABLE);//2. 设置工作模式GPIO_InitTypeDef initDef;initDef.GPIO_Speed= GPIO_Speed_50MHz;initDef.GPIO_Mode = GPIO_Mode_Out_PP;//PA0-PA7initDef.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5  | GPIO_Pin_6 | GPIO_Pin_7;GPIO_Init(GPIOA,&initDef);	//PB3-PB5initDef.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_4 | GPIO_Pin_3;GPIO_Init(GPIOB,&initDef);}

说明一下:

  • 由于数码管和点阵的使用的同一根线,则初始化时直接拷贝过来就行了

 writeColData函数

// 列输入
void writeColData(u8 data)
{// data=1111 1110(第1个led)for(u8 i = 0;i < 8;i++){if(data & 0x01){ // GPIO_WriteBit(GPIOA,GPIO_Pin_0<<i,Bit_SET);// 设置高电平}else{GPIO_WriteBit(GPIOA,GPIO_Pin_0<<i,Bit_RESET);// 设置低电平}data = data >> 1;// data = 0111 111(第8个led)}
}

 说明一下:

  • 点阵的列输入又和跑马灯的程序一致,则直接拷贝过来就行了

 writeRowData函数

// 行输入
void writeRowData(u8 data)
{for(u8 i = 0;i < 8;i++){// 1.数据从高位依次输入SER = data>>7;// 每一次得到数据的最高位// 移位寄存器的时钟线变化SRCLK = 0;delay_us(1);SRCLK = 1;//上升沿信号 移位data <<= 1;// 把已经输入的数据丢弃}// 把数据从移位寄存器 移动到 存储寄存器里面RCLK = 0;delay_us(1);RCLK = 1;// 给一个上升沿信号
}

5. main.c

#include "stm32f10x.h"
#include "led.h"
#include "dzled.h"
#include "systick.h"int main()
{// 滴答定时器SysTick_Init(72);// 初始化dzled_init();// 点亮最左上角的LEDwriteRowData(0x80);// 行只有设置高电平有效writeColData(0x7F);// 列只有设置低电平有效u8 i = 0;while(1){delay_ms(150);}
}

说明一下:

  • 直接调用列输入 行输入就行了

第七节 动力模块->直流电机 

  直流电机是指能将直流电能转换成机械能(直流电动机)或将机械能转换成直流电能(直流发电机)的旋转电机

        直流电机的结构应由定子转子两大部分组成,直流电机没有正负之分,在两端加上直流电就能工作

        开发板配置的直流电机为 5V 直流电机,其主要参数如下:轴长:8mm 轴径:2mm 电压:1-6V 参考电流:0.35-0.4A 3V 转速:17000-18000 转每分钟 外观实物图如下:

1. ULN2003 芯片

        单片机主要是用来控制而非驱动,如果直接使用芯片的GPIO管脚去驱动大功率器件,要么将芯片烧坏,要么就驱动不起来。所以要驱动大功率器件,比如电机。就必须搭建驱动电路,开发板上板载的驱动芯片是ULN2003,该芯片是一个单片高电压、高电流的达林顿晶体管阵列集成电路。不仅可以用来驱动直流电机,还可用来驱动五线四相步进电机,比如28BYJ48 步进电机。

2. 了解电路

 简单来说:使用PB8就行了

结构图

 

原理图

 

3. moto.h

#ifndef _H_MOTO
#define _H_MOTO
#include "stm32f10x.h"
#include "system.h"
#include "systick.h"
// PB8的引脚 - 位带操作
#define MOTO PBout(8)// 初始化电机
void moto_init(void);#endif

4. moto.c

#include "moto.h"// 初始化电机
void moto_init(void)
{// 1. 时钟始能RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);// 2.关闭调试功能GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);// 关闭JTAGGPIO_PinRemapConfig(GPIO_Remap_SWJ_Disable,ENABLE);// 3. 初始化GPIO_InitTypeDef initDef;// 结构体initDef.GPIO_Mode = GPIO_Mode_Out_PP;// 推挽输出initDef.GPIO_Speed = GPIO_Speed_50MHz;initDef.GPIO_Pin = GPIO_Pin_8;GPIO_Init(GPIOB,&initDef);GPIO_SetBits(GPIOB,GPIO_Pin_8);// 设置为高电平}

5. main.c

#include "stm32f10x.h"
#include "led.h"
#include "key.h"
#include "moto.h"
#include "systick.h"int main()
{// 滴答定时器SysTick_Init(72);// 初始化led_init();moto_init();while(1){// 检测矩阵按键中: 那个按键被按下u8 i = keyScan();if(i == 1){// 高低电平之间切换LED1 = !LED1;MOTO = !MOTO;}delay_ms(150);}
}

说明一下:

  • 最终效果:点击矩阵按键上的第一个按键,就可控制第一个led的亮灭电机的启动 

第八节 步进电机 

        步进电机是将电脉冲信号转变为角位移或线位移的开环控制元件

 工作原理

 

单极性

 

 双极性

2.1 28BYJ-48 步进电机简介

28BYJ48 步进电机自带减速器,为五线四相单极性步进电机,直径为28mm,

28BYJ48 电机内部结构等效图如下所示:

28BYJ48 步进电机主要参数如下所示:

        在上图中 28BYJ48 步进电机主要参数中可以看到有一个减速比:1:64,步进角为 5.625/64 度,如果需要转动一圈,那么需要 360/5.625*64=4096 个脉冲信号。 减速比这个和之前介绍的直流减速电机有点类似,所以28BYJ48 步进电机实际上是:减速齿轮+步进电机组成,28BYJ48 步进电机减速齿轮实物图如下所示:  

减速齿轮计算方法如下所示:

2.2 了解电路

1、MOTO IN1-4全部用到,所以端口是PB8-9PB12-13

2、根据原理了解,需要实现的是电位的切换驱动旋转

3、给一个高电平,输出低电平,形成电流环路,产生磁场

结构图

原理图

2.3 moto.h

#ifndef _H_MOTO
#define _H_MOTO
#include "stm32f10x.h"
#include "system.h"
#include "systick.h"
// 位带操作
#define MOTOR_IN1 PBout(8)
#define MOTOR_IN2 PBout(9)
#define MOTOR_IN3 PBout(12)
#define MOTOR_IN4 PBout(13)// 初始化步进电机
void moto_init(void);// 运行步进电机
void motor_run(u8 step,u8 dir,u8 speed,u16 angle,u8 sta);
#endif

参数说明:

  • step表示指定步进控制节拍,可选值4或8
  • dir表示方向选择,其中1表示顺时针,0表示逆时针
  • speed表示速度,可选范围为1-5
  • angle表示角度,可选范围为0-360
  • sta表示运行状态,其中1启动,0停止

2.4 moto.c

#include "moto.h"// 初始化电机
void moto_init(void)
{// 1. 时钟始能RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);// 2.关闭调试功能GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);// 关闭JTAGGPIO_PinRemapConfig(GPIO_Remap_SWJ_Disable,ENABLE);// 3. 初始化GPIO_InitTypeDef initDef;// 结构体initDef.GPIO_Mode = GPIO_Mode_Out_PP;// 推挽输出initDef.GPIO_Speed = GPIO_Speed_50MHz;initDef.GPIO_Pin = GPIO_Pin_8;GPIO_Init(GPIOB,&initDef);initDef.GPIO_Pin = GPIO_Pin_9;GPIO_Init(GPIOB,&initDef);initDef.GPIO_Pin = GPIO_Pin_12;GPIO_Init(GPIOB,&initDef);initDef.GPIO_Pin = GPIO_Pin_13;GPIO_Init(GPIOB,&initDef);
}// 运行步进电机
void motor_run(u8 step,u8 dir,u8 speed,u16 angle,u8 sta)
{// 启动if(sta){// 顺if(dir){// 转动角度所对应的信号个数for(u8 j = 0;j < angle*64/45;j++){// 把整个一圈分为4 / 8节拍// 每个节拍应该怎么转动 电机应该是什么状态for(int i = 0;i < 8;i+=(8/step)){switch (i){case 0: MOTOR_IN1=1;MOTOR_IN2=0;MOTOR_IN3=0;MOTOR_IN4=0;break;case 1: MOTOR_IN1=1;MOTOR_IN2=1;MOTOR_IN3=0;MOTOR_IN4=0;break;case 2: MOTOR_IN1=0;MOTOR_IN2=1;MOTOR_IN3=0;MOTOR_IN4=0;break;case 3: MOTOR_IN1=0;MOTOR_IN2=1;MOTOR_IN3=1;MOTOR_IN4=0;break;case 4: MOTOR_IN1=0;MOTOR_IN2=0;MOTOR_IN3=1;MOTOR_IN4=0;break;case 5: MOTOR_IN1=0;MOTOR_IN2=0;MOTOR_IN3=1;MOTOR_IN4=1;break;case 6: MOTOR_IN1=0;MOTOR_IN2=0;MOTOR_IN3=0;MOTOR_IN4=1;break;case 7: MOTOR_IN1=1;MOTOR_IN2=0;MOTOR_IN3=0;MOTOR_IN4=1;break;}delay_ms(speed);}}}else{// 逆时针// 转动角度所对应的信号个数for(u8 j = 0;j < angle*64/45;j++){// 把整个一圈分为4 / 8节拍// 每个节拍应该怎么转动 电机应该是什么状态for(int i = 0;i < 8;i+=(8/step)){switch (i){case 0: MOTOR_IN1=1;MOTOR_IN2=0;MOTOR_IN3=0;MOTOR_IN4=1;break;case 1: MOTOR_IN1=0;MOTOR_IN2=0;MOTOR_IN3=0;MOTOR_IN4=1;break;case 2: MOTOR_IN1=0;MOTOR_IN2=0;MOTOR_IN3=1;MOTOR_IN4=1;break;case 3: MOTOR_IN1=0;MOTOR_IN2=0;MOTOR_IN3=1;MOTOR_IN4=0;break;case 4: MOTOR_IN1=0;MOTOR_IN2=1;MOTOR_IN3=1;MOTOR_IN4=0;break;case 5: MOTOR_IN1=0;MOTOR_IN2=1;MOTOR_IN3=0;MOTOR_IN4=0;break;case 6: MOTOR_IN1=1;MOTOR_IN2=1;MOTOR_IN3=0;MOTOR_IN4=0;break;case 7: MOTOR_IN1=1;MOTOR_IN2=0;MOTOR_IN3=0;MOTOR_IN4=0;break;}delay_ms(speed);}}}}
}

 2.5 main.c

#include "stm32f10x.h"
#include "led.h"
#include "key.h"
#include "moto.h"
#include "systick.h"int main()
{// 滴答定时器SysTick_Init(72);// 初始化led_init();moto_init();u8 dir = 1;u8 sta = 0;u8 speed = 1;// 取值1-5while(1){// 检测矩阵按键中: 那个按键被按下u8 i = keyScan();if(i == 1){sta = !sta;// 启动/停止}else if(i == 2){dir = !dir;// 正转/反转}else if(i == 3){// 加速度if(speed > 1) speed--;}else if(i == 4){// 减sudoif(speed<5) speed++;}else{delay_ms(10);}motor_run(8,dir,speed,1,sta);delay_ms(150);}
}

 

相关文章:

  • 深度剖析 PACK_SESSIONID 实现原理与安全突破机制
  • Spring Boot的智能装配引擎--自动配置
  • 私有规则库:企业合规与安全的终极防线
  • 【LeetCode#第228题】汇总区间(简单题)
  • 税务 VR 虚拟体验,带来全新办税感受
  • windows下docker虚拟文件大C盘迁移D盘
  • 人工智能学习57-TF训练
  • Shell脚本中和||语法解析
  • tkinter 的 place() 布局管理器学习指南
  • 软件架构的发展历程——从早期的单体架构到如今的云原生与智能架构
  • FPGA基础 -- Verilog 的属性(Attributes)
  • 使用 Isaac Sim 模拟机器人
  • windows清理系统备份文件夹WinSxS文件夹清理
  • tkinter Text 组件学习指南
  • 初学python的我开始Leetcode题10-2
  • 大数据Hadoop集群搭建
  • 加密货币:比特币
  • 结构体的嵌套问题
  • Llama 4 模型卡及提示格式介绍
  • swift-14-可选项的本质、运算符重载、扩展( Extension )
  • 网站长春网站建设/app注册推广团队
  • 做网站建设哪家效益快/网址导航该如何推广
  • 鹰潭网站建设/免费网站安全软件大全
  • 大陆做爰视频网站/新平台推广
  • 国内建站公司/百度app下载安装 官方
  • 广东哪家网站建设后台管理便捷/seo外链在线提交工具