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);}
}

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/87827.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/87827.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

GitHub Copilot 配置快捷键

GitHub Copilot 常用快捷键&#xff08;VS Code&#xff09; 功能快捷键&#xff08;Windows/Linux&#xff09;快捷键&#xff08;macOS&#xff09;接受建议&#xff08;选中的&#xff09;TabTab下一个建议Alt ]Option ]上一个建议Alt [Option [手动触发建议Ctrl Ente…

C++异常处理:深入理解与实践指南

C异常处理&#xff1a;深入理解与实践指南 在现代编程中&#xff0c;异常处理是确保程序健壮性和可靠性的重要机制。C作为一种功能强大的编程语言&#xff0c;提供了丰富的异常处理机制&#xff0c;帮助开发者应对程序运行时可能出现的各种意外情况。本文将深入探讨C异常处理的…

MySQL数据库的类型

文章目录 数值类型tinyint类型bit类型小数类型decimal 日期类型日期和时间类型 字符串类型charvarchar enum和set 数值类型 类型大小范围&#xff08;有符号&#xff09;范围&#xff08;无符号&#xff09;用途TINYINT1 Bytes(-128&#xff0c;127)(0&#xff0c;255)小整数值…

【Docker基础】Docker镜像管理:docker build详解

目录 1 Docker镜像基础概念 1.1 什么是Docker镜像 1.2 镜像的分层结构 2 docker build命令详解 2.1 docker build基本语法 2.2 构建上下文概念 3 Dockerfile编写实践示例 3.1 Dockerfile指令详解 3.1.1 FROM 3.1.2 RUN 3.1.3 COPY vs ADD 3.1.4 CMD vs ENTRYPOINT …

在 macOS 上部署 Akash Network 的完整 Shell 脚本解决方案

以下是在 macOS 上部署 Akash Network 的完整 Shell 脚本解决方案,包含详细注释和错误处理: #!/bin/bash # Akash Network macOS 部署脚本 v2.5 # 功能:在 macOS 系统上完整部署 Akash Network 节点和客户端工具 # 作者:DeepSeek 区块链团队 # 日期:2025-06-20 # 文档:h…

【分布式理论】读确认数与写确认数:分布式一致性的核心概念

文章目录 零、概述一、基本概念解释1、 什么是写确认数&#xff08;w&#xff09;&#xff1f;2、 什么是读确认数&#xff08;r&#xff09;&#xff1f;3、一致性级别的对应关系 二、工作流程详解1、 写操作的完整流程2、 读操作的完整流程 三、强一致性的数学原理1、 为什么…

滚珠导轨在医疗设备中有多重要?

在医疗设备领域&#xff0c;稳定性是保障手术安全、提升诊断精度的核心要素。无论是手术机器人精准的器械操作&#xff0c;还是CT扫描仪高速稳定的扫描运动&#xff0c;都离不开背后精密传动系统的支持。作为线性运动的核心部件&#xff0c;滚珠导轨凭借其独特的滚动摩擦原理与…

港科ISM选课攻略整理

毕业要求 课程和课程目录(ISM专业) "D:\HKUST-ISM\prepare\中英Program & Course Catalog.pdf" 课程和课程目录&#xff08;全部ISOM课程&#xff09; "D:\HKUST-ISM\prepare\全部ISOM Course Catalog.pdf" 两个可选专业方向 Financial Technolo…

rent8_wechat-最常用出租屋管理系统-微信小程序

rent8_wechat-最常用出租屋管理系统是rent8的微信小程序&#xff0c;需要和rent8配合使用。rent8_wechat基于Tdesign开发。 核心功能 房产管理&#xff1a;新增房产信息、修改房产信息、删除房产信息。房间管理&#xff1a;新增房间信息、修改房间信息、删除房间信息、入住管…

OpenCV CUDA模块设备层---- 绝对值函数abs()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 这是 OpenCV 的 cv::cudev 模块中用于 CUDA 设备端&#xff08;device&#xff09;的绝对值函数&#xff0c;专门处理 uchar1 类型&#xff08;即…

IEC61850 通信协议测试验证方法详解

一、MMS 协议测试方法 MMS&#xff08;制造报文规范&#xff09;是 IEC61850 中用于设备监控和控制的核心协议&#xff0c;测试需覆盖以下维度&#xff1a; &#xff08;一&#xff09;协议栈实现验证 连接管理测试 测试用例&#xff1a;建立和释放 MMS 连接 100 次&#xf…

关于 Kyber:抗量子密码算法 Kyber 详解

一、基本概念 后量子密码学&#xff08;PQC&#xff09; │ ├──> 是一个领域&#xff08;研究如何在“量子时代”保护数据安全&#xff09; │ └──> Kyber 是这个领域中设计出来的一个“抗量子密码算法”└──> Kyber 是用于加密密钥交换的算法&#xff08;叫…

如何保障具身智能系统级安全?鸿道OS给出中国方案

由东土科技自主研发完成的鸿道&#xff08;Intewell&#xff09;工业操作系统正式发布。东土科技董事长李平与该公司全资子公司光亚鸿道总经理邹露君在接受第一财经等采访时&#xff0c;解释了如何通过操作系统为具身智能产业提供底层支撑&#xff0c;解决产业规模化落地的安全…

深入浅出:JavaScript ES6中类(Class)的革新与实践

深入浅出&#xff1a;JavaScript ES6中类&#xff08;Class&#xff09;的革新与实践 在JavaScript的发展历程中&#xff0c;ES6&#xff08;ECMAScript 2015&#xff09;无疑是一个里程碑式的版本。它不仅引入了let、const、箭头函数等特性&#xff0c;更通过**类&#xff08…

华大北斗TAU804M-N2B0双频单北斗高精度定位模块 100%国产双频北斗 打破u-blox技术垄断

华大北斗TAU804M-N2B0双频单北斗模块深度解析 1. 产品定位 TAU804M-N2B0 是华大北斗&#xff08;HDSC&#xff09;推出的 双频单北斗高精度定位模块&#xff0c;支持 B1IB2a双频信号接收&#xff0c;专为 高精度定位、抗多径干扰 场景设计&#xff0c;是北斗三号系统应用的标杆…

IP证书申请攻略细则,有何作用?

IP证书申请攻略细则及作用解析 一、IP证书的作用 数据加密传输 IP证书通过SSL/TLS协议对客户端与服务器之间的数据进行加密&#xff0c;防止数据在传输过程中被窃取或篡改&#xff0c;适用于物联网设备、API接口、测试服务器等直接通过IP访问的场景。 身份验证与防伪造 浏览器…

回文链表C++

给你一个单链表的头节点 head &#xff0c;请你判断该链表是否为回文链表。如果是&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 时间复杂度较大的解法&#xff1a; /*** Definition for singly-linked list.* struct ListNode {* int val;* Lis…

限流系列之三:TDMQ for Apache Pulsar 限流技术深度解析

导语 在高速、高吞吐量的消息处理场景中&#xff0c;TDMQ Pulsar 版以其卓越的性能和可扩展性成为众多企业的首选。然而&#xff0c;随着生产者和消费者以极高的速度生产/消费大量消息&#xff0c;服务器资源如 CPU、内存、网络及磁盘 IO 等可能会面临饱和风险。为此&#xff…

非研发部门参与产品开发过程的价值体现

汉捷咨询 胡红卫 企业已经越来越意识到新产品开发项目需要市场、销售、制造、采购、服务、财务等非研发部门的参与&#xff0c;尝试建立跨部门的项目组&#xff0c;安排相关人员参与项目&#xff0c;但是效果如何呢&#xff1f;在汉捷咨询对很多企业调研诊断过程中&#xff0c;…

Kafka的存储与索引:数据处理的底层奥秘

一、引言 Kafka 之所以能在海量数据的传输和处理过程中保持高效的性能和低延迟&#xff0c;背后隐藏着众多精妙的设计&#xff0c;而其存储与索引机制便是其中的核心奥秘。接下来&#xff0c;让我们深入探寻 Kafka 存储机制的基石与架构。 二、分区与日志组织​ Kafka 中的消…