第一讲笔记
网络标签:网络名称
原理图设计,元器件+设计 原理图是示意图,描述网络之间的关系。
PCB设计:布局、布线、电磁兼容。实物图对照。封装绘制、DIP40
电气连接:相同的网络有金属导线进行连接
针对主控单元:网络+外围电路 编程驱动硬件控制等等 嵌入式设备进行软件开发
单片机:相对简单、处理能力有限、内存、Flash等资源有限 51 STC16 STM32
基于ARM架构+某一款
高端CPU:带操作系统,安卓、ios、linux\ 鸿蒙 操作硬件
在确定的电路板上、进行必要的软件开发、实现相应的功能。屏幕显示、温湿度数据采集、温湿度数据上网、app。
软件一般是指程序:C语言计算机二级
C语言基础:
数据类型:
循环语句:for while do while
运算符:
关键字:if else switch case while do for 32关键字
指针类型、数组、字符、整型、浮点、布尔
for循环
写C语言代码,编辑软件、编译代码、下载验证、开发板。KEIL 搭建工程,一系列代码文件集合,是运行我们用户自己编写代码前提。启动文件、配置文件、MCU会提供。单片机应用。
添加.s文件.c文件 必须要有这俩文件 .h文件只需要添加编译路径即可
单片机基础知识:
内核:
ARM-A 性能产品用
ARM-R 军工产品用
ARM-M 工控领域用
ARM-Cortex-M4 STM32F4XXX
ARM-Cortex-M3 STM32F1XXX
ARM-Cortex-M0 STM32F0XXX
外设:
是芯片厂家根据需要设计开发的具有一定功能的电路单元,可以编程。外指芯片内核之外,外设在芯片内部。内核在芯片内。
常见的外设有哪些?
GPIO:
是什么?
DMA
ADC
DAC
TIM1 TIM2
IWDG
WWDG
RTC
EXTI
GPIO 简介
Input输入
output输出
接口
有什么用?
能够进行信息交换,MCU内部跟MCU外部进行信息交互唯一通道
如何为我所有?
信号输出、信号检测、都可以由GPIO来完成。
信号:信号是信息的载体。
信息:我们想要传递的内容。
电路中信号的特征:
0跟1 0是低电平 1是高电平
有规律的1跟0: 载波 串口通信 PWM
检测信号:检测0跟1
STM32F405RGT6这个芯片有多少GPIO,如何分类
100个管脚,LQFP封装
100管脚里面有多少可以当作GPIO呢,电源 、地。
按照字母进行分组:
A组,B组,C组,
每组有16个 16*5 = 80
GPIOA:A0 A1 ...A15
GPIOB:B0 B1 ...B15
GPIOC
GPIOD
GPIOE
接晶体振荡器:PH0 PH1
各个端口PORT,都有十六个IO,依次从0开始编号 0 -15
编程方法:针对某个端口下的某个IO进行
端口的控制器:每个端口都有自己的端口控制器,来管理自己端口下的各个IO,可以通过编写程序实现指定端口指定IO输出(控制)或者输入(检测);
GPIO控制器框图:
先学习如何使用GPIO控制器控制IO输出指定电平
研究如何控制寄存器?
寄存器就是一个变量,通过修改变量的值 写操作,通过读取变量的值 读操作
通过读写寄存器就可以控制GPIO的工作状态;
怎么控制?
GPIO端口模式寄存器:用来管理GPIO的工作模式 4种模式 选择其中一种
通过两个2进制位的排列组合 00 模式1 01模式2 10模式3 11模式4
16个GPIO也就需要16*2 = 32bit STM32 寄存器的位宽是32位 ,分配给了16个IO,按照顺序位置进行分配。
PA0为例:PA0处于模式4 也就是寄存器的bit1 bit0 要修改成11
输出类型控制寄存器
输出数据寄存器:
以控制一个GPIO口输出一个高电平为例:
推挽模式理解:可以输出1也可以输出0的模式
PA0为例:操作三个寄存器
端口模式寄存器的bit1bit0设置成10
端口输出类型寄存器的bit0位设置0
端口输出数据寄存器的bit0位设置1还是设置0
GPIO推挽输出为例如何编程实现?
BEEP:网络标号
数据数据寄存器等于1
PC12 配置成推挽输出模式
输出一个高电平 Q2导通 蜂鸣器电路形成回路 蜂鸣器就会发声
Q2:三极管 NPN
3V3:电源
GND:地
每个端口都有自己的寄存器组,包括模式寄存器、速度寄存器、上下拉寄存器。PC端口模式寄存器应该配置12这个IO口为输出模式,配置输出类型寄存器推挽。
0000 | 0x0 |
0001 | 0x1 |
0010 | 0x2 |
0011 | 0x3 |
0100 | 0x4 |
0101 | 0x5 |
0110 | 0x6 |
0111 | 0x7 |
1000 | 0x8 |
1001 | 0x9 |
1010 | 0xA |
1011 | 0xB |
1100 | 0xC |
1101 | 0xD |
1110 | 0xE |
1111 | 0xF |
1111 0000 0100 1011 1111 1111 1111 1111 | 0xF04BFFFF |
0000 0000 0000 0000 0000 0000 0000 0000 | 0x00000000 |
GPIOC->MODER = 0x0000 0000;
GPIOC->MODER = 0x0100 0000;
GPIOC->MODER = 0x1<<24|0x1<<22|0x1<<20;//仅仅设置了24bit为1 其余各位都是0 PC12 PC11 PC10都设置成这个模式
GPIOC->MODER |=(0x1<<24);
GPIOC->MODER = GPIOC->MODER|(0x1<<24);
GPIOC->MODER |=(0x1<<22);
或操作:
GPIOC0->MODER = 0x1<<22;
GPIOC->OTYPER = 0x0000;
GPIOC->OTYPER &= ~(1<<12);
清除第12位
与操作:
0001 0000 0000 0000
1110 1111 1111 1111
按位取反
1011
1011 = 1<<12
1011
头文件:声明函数 声明变量 声明结构体 等等//为了能够成功引入,需要告诉软件,在哪里可以找到该文件
/ exact-width signed integer types /
typedef signed char int8_t;
typedef signed short int int16_t;
typedef signed int int32_t;
typedef signed __INT64 int64_t;
/ exact-width unsigned integer types /
typedef unsigned char uint8_t;
typedef unsigned short int uint16_t;
typedef unsigned int uint32_t;
typedef unsigned __INT64 uint64_t;
/ 7.18.1.2 /
/ smallest type of at least n bits /
/ minimum-width signed integer types /
typedef signed char int_least8_t;
typedef signed short int int_least16_t;
typedef signed int int_least32_t;
typedef signed __INT64 int_least64_t;
/ minimum-width unsigned integer types /
typedef unsigned char uint_least8_t;
typedef unsigned short int uint_least16_t;
typedef unsigned int uint_least32_t;
typedef unsigned __INT64 uint_least64_t;
选择文件夹:就是指该文件下有需要包含的头文件
C文件:函数实现 变量定义 结构体引用 等等
/*
函数作用:配置蜂鸣器管脚PC12,配置成推挽输出模式
函数名字:BEEP_Config
函数参数:void
函数返回:void
配置模式寄存器: 输出模式 01
00:输入(复位状态)
01:通用输出模式
10:复用功能模式
11:模拟模式
配置输出类型寄存器:推挽输出 0
0:输出推挽(复位状态)
1:输出开漏
配置端口输出数据寄存器:输出1/输出0 默认输出0
*/
void BEEP_Config(void)
{
GPIOC->MODER |= (0x1<<24); //目的是让寄存器的PC12 25:24 01
GPIOC->OTYPER &= ~(0x1<<12); //目的是让寄存器的PC12 12 0
// GPIOC->ODR |= (0x1<<12); //目的是让寄存器的PC12 12 1 ->输出高电平
GPIOC->ODR &= ~(0x1<<12); //目的是让寄存器的PC12 12 0 ->输出低电平
}
/*
函数作用:开关蜂鸣器
函数名字:BEEP_Ctrl
函数参数:uint8_t State
函数返回:void
*/
void BEEP_Ctrl(uint8_t State)
{
if(State)
{
GPIOC->ODR |= (0x1<<12); //目的是让寄存器的PC12 12 1 ->输出高电平
}
else
{
GPIOC->ODR &= ~(0x1<<12); //目的是让寄存器的PC12 12 0 ->输出低电平
}
}
#ifndef _BEEP_H_ //预编译阶段头文件
#define _BEEP_H_
#include "stm32f4xx.h"
void BEEP_Config(void);//函数声明 加分号
void BEEP_Ctrl(uint8_t State);
#endif
RAM和ROM的区别
RAM (随机存取存储器,Random Access Memory):断电之后存储的数据消失,应用:CPU缓存、电脑和手机的内存
DRAM (动态RAM,Dynamic RAM):只需一个晶体管和一个电容来存储一个0或1。
SRAM (静态RAM,Static RAM):需要6个或更多的晶体管来存储一个0或1。
ROM (Read-only memory,只读存储器):断电之后数据仍然存在,因为在存储电荷的周围有绝缘层,这个绝缘层可以让存储在里面的电荷长时间不消失。应用:CD-ROM, DVD-ROM
PROM (可编程只读存储器,programmable read only memory):英语学习机
EAROM(电可改写只读存储器,electrically altherable read only memory)
EPROM(可擦可编程只读存储器,erasable programmable read only memory)
EEPROM(电子式可擦可编程只读存储器,electrically erasable programmable read only memory):闪存,U盘,固态硬盘
//8421
//0110 = 4 = 1*2^2+1*2^1
//1239.5 = 1230 = 1*10^3+2*10^2+3*10^1+9*10^0+5*10^(-1)
0000 0000 0000 0000 0000 0000 0100 0001 =0x41
//或逻辑 ||
//有真则真 全假才假
//表达式1||表达式2||表达式3
//与逻辑
//全真为真 有假则假
//表达式1&&表达式2&&表达式3
//非逻辑
//真变假 假变真
//!(表达式1)
//0是假
//1是真 2也是真 3也是真
//按位与 表达式1&表达式2
0000 0000
&0000 0001
0000 0000
1 0 1 0
0 0 1 1
0 0 1 0
任何一个二进制数跟0相与结果一定是0 //近墨者黑 //与0危险 会发生改变
任何一个二进制数跟1相与结果一定不发生改变:y与1安全
//按位或 表达式1|表达式2
0000 0000
|0000 0001
0000 0001
1 0 1 0
1 1 0 0
1 1 1 0
任何一个二进制数跟1相或结果一定是1 //近朱者赤 //或1危险 会发生改变
任何一个二进制数跟0相或结果一定不发生改变 //或0安全
1<<2: 00000100
//按位取反 ~(表达式1)
0000 0000
~1111 1111
如何设置某个寄存器的指定1位n值为1
reg | (1<<n);
如何设置某个寄存器的指定1位n值为0
reg & ~(1<<n);
如何设置某个寄存器的指定2位n值为11
reg | (3<<n);
如何设置某个寄存器的指定2位n值为0
reg & ~(3<<n);
如何设置某个寄存器的指定2位n值为10 01
reg & ~(3<<n);//打扫屋子在请客
reg | (2<<n);
reg & ~(3<<n);
reg | (1<<n);
如何设置某个寄存器的指定2位n值为0
reg & ~(3<<n);
/*
函数作用:2进制形式打印无符号整型数据 10进制%d %x %o
函数名字:printf_2
*/
void printf_2(unsigned char num)
{
int i = 0;
for(i= 8;i>0;i--)
{
if(num&1<<i-1)
{
printf("1");
}
else
{
printf("0");
}
}
printf("\n");
}
//主函数入口
int main(void)
{
int i = 0;
unsigned char REG = 0; //00000000
printf_2(REG);
unsigned char VAL = 1; //00000001
printf_2(VAL);
REG |= VAL;//10000000
printf_2(REG);
REG |= 3<<6;//11000000
printf_2(REG); //11000001
//11000000 ~
//00111111
REG &= (~(3<<6));//00000001
//11111110
//00000001
printf_2(REG);
REG &= ~(1<<0);//11111110
printf_2(REG);
// for(i = 0;i<8;i++)
// {
// printf_2(1<<i);
// }
}
//10000001 -1的原码
//11111110 -1的反码 补码 反码+1
//11111111 -1的补码
计算机存储数据是以补码进行
正数:0代表符号位
原码
反码
补码
三者形式完全统一
负数:1代表负数符号位
原码1是符号位,后面是二进制
反码是在符号位不变的情况下其余各位取反
补码:在反码的基础上加1
KEY2
KEY1检测的是高电平
KEY2检测的是低电平
KEY3检测的是低电平
对应端口寄存器 输入数据寄存器 IDR
GPIOC->IDR
串行通信原理及代码实现
串口:仿真Debug 打印调试信息帮助我们查找错误
通信的接口,信息交互的通道,有规律的信息,发生一个字符,发送一个十六进制
发送一个字符串。二进制。
TTL:晶体管晶体管逻辑电平
高电平:代表逻辑1
低电平:代表逻辑0
“HELLO WORLD”H的二进制 HELLO WORLD 字符的二进制数据流。
每秒传输一个数据位,高电平代表1,低电平代表0 发送一个0x0F;
八个数据分8次传输,GPIO ODR 0 0 0 0 1 1 1 1
通信的本质仍然是传输高低电平。起始位+数据位+可有可无的校验位+1位的停止位
按照某种协议进行数据包装。
协议是一种约定,约定数据是什么样子如何发送。
高电平到低电平叫下降沿
低电平到高电平叫上升沿
发送高电平低电平的速度如何描述:每秒钟传输1或者0的个数 8bps
4*1024Byte = 4*1024*8bit /s bps 9600bps 115200bps
A发送B接收 单工通信 发送的一方和接收的一方是固定的。
B发送A接收 单工通信 发送的一方和接收的一方是固定的
STM32串口 既可以由A发送也可以由B到A发送 双工通信。
全双工:发送接收可以同时
半双工:发送也可以接收也可以但是不能同时。
了解不了解,STM32 全双工异步串口。 串行和并行都是通信常用方式,串行数据线少
传输的效率相对不高,并口的数据线相对较多,而且速度相对较快。
STM32的串口如何使用?串口的控制器如何使用?
串口的工作框图
STM32串口是特殊的几个GPIO
对应的寄存器影响工作状态
数据寄存器 DR
接收其他设备发送来的数据,把自己的数据通过DR传输到发送管脚。
控制寄存器
状态寄存器
波特率发生器寄存器
等等
帧格式:起始位+数据位+校验位+停止位
传输的过程中1的个数是奇数个还是偶数个 奇数个就是奇校验 偶数个就是偶校验
奇数偶数校验位 可以不校验
1110 0000 0 4个1 遵循奇校验
1111 0101 1 1110 0101 1 6个
添加开启库函数的宏定义
添加库函数所在的头文件路径
STM32F40_41xxx,USE_STDPERIPH_DRIVER
串口1配置
串口1引脚:
USART1_TXD
USART1_RXD
串口2配置
中断是一种处理机制:
第一步确定使用什么中断
接收中断
空闲中断 HELLO
打开中断的使能 库函数使某个控制位打开
很多中断需要响应的时候、可以把这些中断进行分组
抢占优先级:优先级越高可以抢断正在处理中断进程 能不能给抢断
次级优先级:在抢占优先级相同的情况下 次级优先级越高代表越高
练习实现:发送指令控制设备
发送:LED1_ON LED1灯打开
发送:LED1_OFF LED1灯关闭
其他的自己定义即可
舵机是一个角度控制的设备
通过调节一个方波的占空比来进行
0.5/20*100% = 2.5%
2.5/20*100% =12.5%
总时间是20ms,2.5%的输出高电平就可以控制在0度
总时间是20ms,12.5%的时间输出高电平可以控制在180度
时间跟计数数量有关系,还同时跟计数的频率有关系;定时器是一个定时计数的外设,它的作用就是计数,计数频率可以调节。计数频率如何调节?频率变慢叫分频,所谓分频把频率经过一个分频器把频率降低,降低的水准可以编程。
预分器值寄存器:作用调节频率
舵机信号接到了STM32的哪一个定时器,一个定时器有四个输入输出通道,输出通道,
在哪个定时器的哪个通道CHx 编程就是针对某个定时器的某个输出通道,通过调节频率分频值来影响计数的时间。
装载值寄存器:作用影响计数的长短 在确定频率下计数,计数越多时间越长,计数值越小时间越短。
计数20ms 需要20000个数,高电平时间计数值 介于20000*2.5%到20000*12.5%之间 舵机可以调节0-180度
20*1000个数,20*1 ms ,计数1000个需要1ms.计数一个1us;
计数频率多少?计数频率是1MHz;
TIM2_CH2:
TIM2->CCR2;//
TIM2->ARR;//定时器装载值20000-1 一个周期计数多少 20000 次计数 0-20000-1
TIM2->CNT;//定时器当前计数值 介于0-20000-1 之间
TIM2->PSC;//预分频值 168MHz /0-65535之间 【168-1】
定时器之前的频率是多少?
TIM2_挂在APB1
APB1 时钟是42MHz
APB1外设时钟 = 42Mhz
APB1定时器
要么等于APB1外设时钟
要么等于APB1外设时钟的2倍频 42*2 = 84M /84
2.
第一组:
定时器的计数值小于比较直的时候
0-500这段时间,有效状态——高电平
500-20000这段时间是无效状态-低电平
定时器的计数值小于比较直的时候
0-500这段时间,有效状态——低电平
500-20000这段时间是无效状态-------高电平 500/2000
20000-500/20000
定时器的计数值小于比较直的时候
0-500这段时间,无效状态——低电平
500-20000这段时间是无效状态-高电平
CCR =500
递增模式:0-arr
三原色:可以混合任意颜色
八位红色 八位绿色 八位蓝色
24bit
控制24bit的信号是多好
R G B
11111111 11111111 00000000 信号就代表一个黄色。
高电平是1
低电平是0
HHHHHHHH HHHHHHHH LLLLLLLL
逻辑1:高电平时间长度(580ns-1us)+低电平时间长度(580ns-1us) = T1H+T1L
逻辑0:高电平时间长度(220ns-380us)+低电平时间长度(580ns-1us) =T0H+T0L
RESET:低电平时间280us以上
SET_COLOR(R,G,B)
for(I=0;I<8;I++)
{
if(G&0x80>>i)
{
逻辑1:
}
else
{
逻辑0:
}
}
for(I=0;I<8;I++)
{
if(R&0x80>>i)
{
逻辑1:
{
输出一个1;
维持一段时间 看手册
输出一个0
维持一段时间
}
}
else
{
逻辑0:信号 这是信号特征用程序代码实现
{
输出一个1;
维持一段时间 看手册 跟逻辑1时间不一样
输出一个0
维持一段时间
}
}
}
for(I=0;I<8;I++)
{
if(R&0x80>>i)
{
逻辑1:
}
else
{
逻辑0:
}
}
for(I=0;I<8;I++)
{
if(B&0x80>>i)
{
逻辑1:
}
else
{
逻辑0:
}
}
WS2812B_GPIO_Config();//类似LED配置
BIT_0(void)
{
ODR
delay
ODR
DELAY
}
BIT_1(void);
WS2812B_SetColor(U8R,U8G,U8B);
WS2812B_RESET()
//LCD屏幕所需要使用的所有GPIO端口跟管脚
//LCD时钟线
#define LCD_SCLK_PORT GPIOB
#define LCD_SCLK_PIN GPIO_Pin_13
//LCD数据线
#define LCD_MOSI_PORT GPIOB
#define LCD_MOSI_PIN GPIO_Pin_15
//LCD命令数据切换引脚
#define LCD_DC_PORT GPIOD
#define LCD_DC_PIN GPIO_Pin_2
//LCD背光控制线
#define LCD_BLK_PORT GPIOA
#define LCD_BLK_PIN GPIO_Pin_15
//LCD片选线
#define LCD_CS_PORT GPIOB
#define LCD_CS_PIN GPIO_Pin_14
#define LCD_SCLK(X) X?(GPIO_SetBits(LCD_SCLK_PORT,LCD_SCLK_PIN)):(GPIO_ResetBits(LCD_SCLK_PORT,LCD_SCLK_PIN))
#define LCD_MOSI(X) X?(GPIO_SetBits(LCD_MOSI_PORT,LCD_MOSI_PIN)):(GPIO_ResetBits(LCD_MOSI_PORT,LCD_MOSI_PIN))
{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},
{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x80,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},/*"一",0*/
/* (16 X 16 , 宋体 )*/
一(0)
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"一",0*/
/* (16 X 16 , 宋体 )*/
1111111 0111 11111
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"一",0*/
11111 1111 1111 1110
16*16= 256bit
256/8= 16*16/8=16*2=32字节
I2C_SCL 时钟线
I2C_SDA 时钟线
二者都为高电平的时候 SDA有一个下降沿
I2C协议
协议就是一种约定大家需要遵守
I2C_Start()
开始信号 I2C协议的开始通信
当SCL为高的时候 SDA有一个上升沿
I2C协议
协议就是一种约定大家需要遵守
I2C_Stop()
开始信号 I2C协议的开始通信
I2C_W
I2C_R
读地址 = 7位地址+1个读方向位 1
写地址= 7位地址+1个写方向位 0
I2C_SEND
SDA 高 低 数据 是 1 还是 0
SCL时钟下送走
低电平修改数据的值 高点平读数据结果
I2C_RECV