Mrli
别装作很努力,
因为结局不会陪你演戏。
Contacts:
QQ博客园

玩玩Stm32

2019/10/18 嵌入式
Word count: 4,400 | Reading time: 19min

玩玩Stm32

文件结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
G:.
├───CORE # startup_stm32f10x_hd.s汇编编写的启动文件
| # core_cm3.c底层函数
├───HARDWARE # 相关外设的初始化代码
├───OBJ
├───STM32F10x_FWLib # 固件库包: GPIO/i2c/...
│ ├───inc
│ └───src
├───SYSTEM # 正点原子提供的常用、通用模块
│ ├───delay
│ ├───sys
│ └───usart
└───USER # stm32f10x_it.c 中断管理文件
| # stm32f10x.h
├───Listings
└───Objects

编写规范:

用户编写的执行代码写在main.c中,其中#include "stm32f10x.h"作用相当于C51的#include <reg51.h>,是操作寄存器的主要固件库文件,在任何地方引用到固件库函数时都需要导入这个文件。

stm32f10x_it.c、stm32f10x_it.h, 专门存放中断服务函数的C文件 ,大多中断函数都 写在此文件中,方便 管理中断函数,但并不是一定要写在这里面。

GPIO

◆端口复用功能
STM32的大部分端口都具有复用功能。
所谓复用,就是一些端口不仅仅可以做为通用lO口,还可以复用为一些外设引脚,比如PA9,PA10可以复用为STM32的串口1引脚。
▲作用:最大限度的利用端口资源

◆端口重映射功能
就是可以把某些功能引脚映射到其他引脚。
比如串口1默认引脚是PA9,PA10可以通过配置重映射映射到PB6,PB7
作用:为了方便布线

▲所有I0口都可以作为中断输入

工作模式:

  • 推挽输出:可以输出强高低电平
  • 上拉输入: 一端是接地低电平,所以默认情况下另一端需要检测到高电平(按键扫描中,三个引脚需要设置为IPU,按下时<==>输入口检测到低电平)
  • 下拉输入:(按下时<==>输入口检测到低电平)

GPIO重要函数

1
2
3
4
5
6
7
8
9
10
11
12
13
//1个初始化函数:
void GPIO_Init(GPIO_TypeDef* GPIOx,GPIO_InitTypeDef* GPIO_InitStruct);
//2个读取输入电平函数:
uint8t GPIO_ReadlinputDataBit(GPIO TypeDef* GPIOx,uint16_t GPIO_Pin);
uint16_t GPIO_ReadinputData(GPIO_TypeDef* GPIOx);
//2个读取输出电平函数:
uint8t GPIO_ReadOutputDataBit(GPiO_TypeDef* GPiOx,uint16_t GPIO_Pin);
uint16t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx);
//4个设置输出电平函数:前两个常用,后两个不常用
void GPIO_SetBits(GPIOTypeDef* GPIOx, uint16_t GPIOPin);
void GP1O_ResetBits(GPIOTypeDef GPIOx,uint16_t GPIOPin);
void GPIO_WriteBit(GPIOTypeDef* GPIOx,uint16_t GPIO_Pin,BitAction BitVal);
void GPIO_Write(GPIOTypeDef* GPIOx, uint16_t PortVal)

具体说明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct)

/*
GPIO_TypeDef为GPIO寄存器组合的类型
typedef struct{
__IO uint32_t CRL;
__IO uint32_t CRH;
__IO uint32_t IDR;
__IO uint32_t ODR;
__IO uint32_t BSRR;
__IO uint32_t BRR;
__IO uint32_t LCKR;
} GPIO_TypeDef;
GPIOx的选择可以为GPIOA->GPIOG
*/

/*
typedef struct{
uint16_t GPIO_Pin;
GPIOSpeed_TypeDef GPIO_Speed;
GPIOMode_TypeDef GPIO_Mode;
}GPIO_InitTypeDef;
*/

初始化示例

1
2
3
4
5
6
7
8
9
10
// 声明结构体变量
GPIO_InitTypeDef GPIO_InitStructure;
//LEDO-->PB.5端口配置
GPIO InitStructure.GPIO Pin =GPIO_Pin_5;
//推挽输出
GPIO InitStructure.GPIO Mode=GPIO_Mode_Out_PP;
//IO口速度为50MHz
GPIO InitStructure.GPIO Speed=GPIO_Speed_50MHz;
//根据设定参数初始化GPIOB.5
GPIO_Init(GPIOB,&GPIO_InitStructure);

▲在使用GPIO前,需要使能IO口时钟,调用函数RCC_APB2PeriphColckCmd();

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState)
/*RCC_APB2Periph 可以为
RCC_APB2Periph_AFIO
RCC_APB2Periph_GPIOA
RCC_APB2Periph_GPIOB
RCC_APB2Periph_GPIOC
RCC_APB2Periph_GPIOD
RCC_APB2Periph_GPIOE
RCC_APB2Periph_GPIOF
RCC_APB2Periph_GPIOG
RCC_APB2Periph_ADC1
RCC_APB2Periph_ADC2
RCC_APB2Periph_TIM1
RCC_APB2Periph_SPI1
RCC_APB2Periph_TIM8
RCC_APB2Periph_USART1
RCC_APB2Periph_ADC3
RCC_APB2Periph_TIM15
RCC_APB2Periph_TIM16
RCC_APB2Periph_TIM17
RCC_APB2Periph_TIM9
RCC_APB2Periph_TIM10
RCC_APB2Periph_TIM11

NewState 为ENABLE / DISABLE
*/

提示:不能通过IO口直接驱动大功率器件。

△复位之后,IO口默认为浮空状态,如果不接下拉电阻,那么电平不确定为高还是低电平。(到是小电流的时候,电流会直接通过下拉电阻到地,不会经过三极管;只有电流足够大,才会经过三极管)

demo : 跑马灯实验

跑马灯

当将PE5设置为低电平时,通过上拉电阻连到VCC后,LED就能点亮。PE5被设置为高电平时与上拉高电平之间没有压差,此时LED熄灭。

完整代码:

led.c文件内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include "led.h"
#include "stm32f10x.h"
// 在任何地方引用到固件库时都需要导入这个文件

void LED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOE,ENABLE);

GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOB,&GPIO_InitStruct);

GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOE,&GPIO_InitStruct);

// 设置为高电平,熄灭
GPIO_SetBits(GPIOB, GPIO_Pin_5);
}

main.c文件内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include "stm32f10x.h"
#include "led.h"
#include "delay.h"

int main(void){
delay_init();
LED_Init();
while(1){
GPIO_SetBits(GPIOB,GPIO_Pin_5);
GPIO_SetBits(GPIOE,GPIO_Pin_5);
delay_ms(500);
GPIO_ResetBits(GPIOB,GPIO_Pin_5);
GPIO_ResetBits(GPIOE,GPIO_Pin_5);
delay_ms(500);
}
}

操作IO口的三种方式:

  • 位操作:#define BEEP PBout(8);BEEP = 1
  • 库函数:GPIO_SetBits(GPIOB, GPIO_Pin_8);
  • 寄存器:

中断管理

对STM32中断进行分组,组0~4。同时,对每个中断设置一个抢占优先级和一个响应优先级值。IP bit决定了对每个中断共有2^4(位) = 16级的中断优先级设置

中断分组

  • 高优先级的抢占优先级是可以打断正在进行的低抢占优先级中断的。
  • 抢占优先级相同的中断,高响应优先级不可以打断低响应优先级的中断。
  • 抢占优先级相同的中断,当两个中断同时发生的情况下,哪个响应优先级高,哪个先执行。
  • 如果两个中断的抢占优先级和响应优先级都是一样的话,则看哪个中断先发生就先执行;

总结:中断嵌套执行看抢占优先级;占优先级相同时,响应优先级高的先响应;两者都一样的话,执行顺序看发生的时间

△.优先级0最高,4最低。

▲.系统代码执行过程中,只设置一次中断优先,一般不会再改变分组。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 中断优先级分组函数
void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup)
// demo: NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2)

// 对某个中断设置优先级
void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct)
/*
typedef struct{
uint8_t NVIC_IRQChannel;
uint8_t NVIC_IRQChannelPreemptionPriority;
uint8_t NVIC_IRQChannelSubPriority;
FunctionalState NVIC_IRQChannelCmd;
} NVIC_InitTypeDef;
*/

中断优先级控制的寄存器组:IP[240]对每个中断进行管理,STM32F10x系列一共有60个可屏蔽中断。全称是:Interrupt Priority Registers

中断优先级设置步骤

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//①统运行后先设置中断优先级分组。调用函数://整个系统执行过程中,只设置一次中断分组。
void NVIC_Priority_GroupConfig(uint32_t NVIC_PriorityGroup);

//②针对每个中断,设置对应的抢占优先级和响应优先级:
void NVIC Init(NVIC_InitTypeDef* NVIC_Initstructy;
/* demo:
NVIC_InitStructure.NVIC_IRQChannel=EXTI3_IRQn://使能按键KEY1所在的外部中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0x02://抢占优先级2
NVIC_InitStructure.NVIC_IRQChannelSubPriority =0x01:
∥字优先级1
NVIC_InitStructure.NVIC_IRQChannelCmd =ENABLE://使能外部中断通道
NWIC_Init(&WIC_Init Structure):/根据NIC_InitStruct中指定的参数初始化外设NVIC寄存器
*/

//③如果需要挂起/解挂,查看中断当前激活状态,分别调用相关函数即可。

串口通信

异步: 跟系统时钟无关

同步: 跟系统时钟有关

波特率计算方法:Tx/RxBaudrate=fPCLKx(16USARTDIV)\mathrm{Tx} / \mathrm{Rx} \quad Baud rate=\frac{f_{P C L K x}}{(16 * U S A R T D I V)}

baud_rate配置的一般步骤:

串口配置的一般步骤

  1. 串口作为外设,需要使能:RCC_APB2PeriphClockCmdO;、以及使能GPIO的时钟
  2. GPIO端口模式设置GPIOInit0;,模式设置为GPIO_Mode_AFPP复用推挽(PA.9/10复用为串口1)
  3. 串口参数初始化
  4. 使能串口USART Cma);
  5. 串口数据收发

UART串口通信只需连接TX,RX,GND一般不需要连接VCC

A:TX、RX是正负压的,所以有个地做参考就行了

A: 通信两端一般都有各自的供电电压,所以不需要VCC,只有一端没有电源的情况下才会用VCC向对方输送电源

A:就像像耳机只要联地、音频左、音频右,而不联vcc一个道理

正点原子提供的USART库:

以回车换行结束的协议

usart.h

1
2
3
4
5
6
7
#define USART_REC_LEN  			200  	//定义最大接收字节数 200
#define EN_USART1_RX 1 //使能(1)/禁止(0)串口1接收

extern u8 USART_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符
extern u16 USART_RX_STA; //接收状态标记
//如果想串口中断接收,请不要注释以下宏定义
void uart_init(u32 bound);

USART_RX_STA

数据全保存在USART_RX_BUF中。根据STA的有效数据个数比如50个,将USART_RX_BUF中前50个数据拿出处理。处理完所有标志位将被清零

▲程序要求,发送的字符是以回车换行结束(Ox0D,0x0A)。

△串口调试助手里勾选"发送新行"选项

usart.c 程序理解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
void USART1_IRQHandler(void)                	//串口1中断服务程序
{
u8 Res;
#if SYSTEM_SUPPORT_OS //如果SYSTEM_SUPPORT_OS为真,则需要支持OS.
OSIntEnter();
#endif
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中断(接收到的数据必须是0x0d 0x0a结尾)
{
Res =USART_ReceiveData(USART1); //读取接收到的数据(单个字符)

if((USART_RX_STA&0x8000)==0)//没收到\n,即接收未完成
{
if(USART_RX_STA&0x4000)//接收到了0x0d(\r)
{
if(Res!=0x0a)USART_RX_STA=0;//如果下一个不是\n,那么接收错误,重新开始
else USART_RX_STA|=0x8000; //如果接受到\n,则接收完成,将USART_RX_STA bit15置1
}
else //还没收到0X0D,即处理真正数据
{
// 如果当前接收到\r,那么将Bit14置1
if(Res==0x0d)USART_RX_STA|=0x4000;
else
{
// 将当前收到的字符Res存到数组USART_RX_BUF保存
USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;
// 索引+1
USART_RX_STA++;
// 如果数据超额,那么判断为接收错误
if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收数据错误,重新开始接收
}
}
}
}
#if SYSTEM_SUPPORT_OS //如果SYSTEM_SUPPORT_OS为真,则需要支持OS.
OSIntExit();
#endif
}
  • Res =USART_ReceiveData(USART1);获得的是当前接收的字符,如果使用中断,那么调用USART_SendData(USART1, Res)就能接收一个字符,发送一个字符。
  • USART_RX_BUF的作用是,保存一次字符串发送过来的所有数据
  • USART_RX_STA是个寄存器,通过Bit14,Bit15来判断接收是否有效

main.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
int main(void){		
u16 t;
u16 len;
u16 times=0;
delay_init(); //延时函数初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
uart_init(115200); //串口初始化为115200
LED_Init(); //LED端口初始化
KEY_Init(); //初始化与按键连接的硬件接口
while(1){
if(USART_RX_STA&0x8000){
len=USART_RX_STA&0x3fff;//得到此次接收到的数据长度
printf("\r\n您发送的消息为:\r\n\r\n");
for(t=0;t<len;t++){
USART_SendData(USART1, USART_RX_BUF[t]);//向串口1发送数据
while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);//等待发送结束
}
printf("\r\n\r\n");//插入换行
USART_RX_STA=0;
}else{
times++;
if(times%5000==0){
printf("\r\n战舰STM32开发板 串口实验\r\n");
printf("正点原子@ALIENTEK\r\n\r\n");
}
if(times%200==0)printf("请输入数据,以回车键结束\n");
if(times%30==0)LED0=!LED0;//闪烁LED,提示系统正在运行.
delay_ms(10);
}
}
}

▲printf可以将发送到串口,默认是USART1,如果需要修改,在usart.c的fputc函数中,将USART1修改即可

外部中断

每个IO口都可以作为外部中断输入

IO与中断线的映射,16* 7 = 112, 一共有16个中断线

Q:什么是中断线,能干什么? A:中断线能发出中断请求

△.同一时刻只有一个引脚能映射到某根中断线

原理:

GPIOX.0映射到EXT10
GPIOX.1映射到EXT11
GPIOX.15映射到EXTI15
e.g.PA.0~PG.0可以映射到EXIT0

I0口外部中断在中断向量表中只分配了7个中断向量,也就是只能使用7个中断服务函数

常用库函数

1
2
3
4
5
6
7
8
9
void GPIO_EXTILineConig(uint8_t GPIO,uint8_t PortSource,uint8_t GPIO_PinSource)
//设置IO口与中断线的映射关系:
exp:GPIO_EXTILineContig(GPIO_PortSourceGPIOE, GPIO_PinSource2)
void EXTIInit(EXTI_InitTypeDef* EXTI_InitStruct);
//初始化中断线:触发方式等
ITStatus EXTI_GetlTStatus(uint32_t EXTI_hLine);
//判断中断线中断状态,是否发生
void EXTI_ClearlTPendingBit(uint32_t EXTI_Line)
//清除中断线上的中断标志位
1
2
3
4
5
EXTI_InitStructure.EXTI_Line=EXTI_Line2;// 指定要配置的中断线
EXTI_InitStructure.EXTI_Mode =EXTI_Mode_Interrupt;// 模式:事件or中断
EXTI_InitStructure.EXTI_Trigger =EXTI_Trigger_Faling;//上升沿、下降沿、双触发沿
EXTI_InitStructure.EXTI_LineCmd =ENABLE;// 使能、失能
EXTI_Init(& EXTI_InitStructure);

配置的一般步骤

外部中断

demo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
void EXTIX_Init(void){
// 声明初始化结构体变量
EXTI_InitTypeDef EXTI_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;

KEY_Init(); // 按键端口初始化

RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); //使能复用功能时钟

//GPIOE.2 中断线以及中断初始化配置 下降沿触发
GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource2);

EXTI_InitStructure.EXTI_Line=EXTI_Line2; //KEY2
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure); //根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器

// ▲由于参数一致,所以不需要修改EXTI_InitStructure的功能参数
//GPIOE.3 中断线以及中断初始化配置 下降沿触发 //KEY1
GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource3);
EXTI_InitStructure.EXTI_Line=EXTI_Line3;
EXTI_Init(&EXTI_InitStructure); //根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器


//GPIOA.0 中断线以及中断初始化配置 上升沿触发 PA0 WK_UP
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0);

EXTI_InitStructure.EXTI_Line=EXTI_Line0;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
EXTI_Init(&EXTI_InitStructure); //根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器


NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; //使能按键WK_UP所在的外部中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02; //抢占优先级2,
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x03; //子优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道
NVIC_Init(&NVIC_InitStructure);

NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQn; //使能按键KEY2所在的外部中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02; //抢占优先级2,
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02; //子优先级2
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道
NVIC_Init(&NVIC_InitStructure);


NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQn; //使能按键KEY1所在的外部中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02; //抢占优先级2
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01; //子优先级1
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道
NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
}



//外部中断2服务程序
void EXTI2_IRQHandler(void){
delay_ms(10);//消抖
if(KEY2==0) //按键KEY2
{
LED0=!LED0;
}
EXTI_ClearITPendingBit(EXTI_Line2); //清除LINE2上的中断标志位
}
//外部中断3服务程序
void EXTI3_IRQHandler(void)
{
delay_ms(10);//消抖
if(KEY1==0) //按键KEY1
{
LED1=!LED1;
}
EXTI_ClearITPendingBit(EXTI_Line3); //清除LINE3上的中断标志位
}

void EXTI4_IRQHandler(void){
delay_ms(10);//消抖
if(KEY0==0) //按键KEY0
{
LED0=!LED0;
LED1=!LED1;
}
EXTI_ClearITPendingBit(EXTI_Line4); //清除LINE4上的中断标志位
}

main.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int main(void) {		
delay_init(); //延时函数初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
uart_init(115200); //串口初始化为115200
LED_Init(); //初始化与LED连接的硬件接口
BEEP_Init(); //初始化蜂鸣器端口
KEY_Init(); //初始化与按键连接的硬件接口
EXTIX_Init(); //外部中断初始化
LED0=0; //点亮LED0
while(1){
printf("OK\r\n");
delay_ms(1000);
}
}

附录:

u8、u16、Size_t是什么类型?

u8、u16

1
2
3
4
5
6
7
8
9
/*!< Signed integer types  */
typedef signed char int8_t; //有符号8位数
typedef signed short int16_t; //有符号16位数
typedef signed long int32_t; //有符号32位数

/*!< Unsigned integer types */
typedef unsigned char uint8_t; //无符号8位数
typedef unsigned short uint16_t; //无符号16位数
typedef unsigned long uint32_t; //无符号32位数

size_t

size_t是C++标准在stddef.h中定义的。这个类型足以用来表示对象的大小。size_t的真实类型与操作系统有关。size_t在32位架构上是4字节,在64位架构上是8字节,在不同架构上进行编译时需要注意这个问题。而int在不同架构下都是4字节,与size_t不同;且int为带符号数,size_t为无符号数。

电平相关知识

单片机是一种数字集成芯片,数字电路中只有两种电平高电平和低电平。为了让大家在刚起步的时候对电平特性有一个清晰的认识,我们暂且定义单片机输出与输入为TTL电平,其中高电平为+5V,低电平为0V。计算机的串口为RS-232C电平。这里要强调的是,RS-232C电平为负逻辑电平。因此当计算机与单片机之间要通信时,需要加电平转换芯片,我们在TX-1C单片机实验板上所加的电平转换芯片是MAX232 。

常用的逻辑电平有TTL、CMOS、LVTTL、ECL、PECL、 GTL 、RS-232. RS-422. RS-485、LVDS等.其中TTL和CMOS的逻辑电平按典型电压可分为四类:5V系列(5V TL和5V CMOS)、3.3V 系列,2.5V 系列和1.8V系列,

T电平信号用的最多,这是因为,数据表示通常采用二进制,+5V等价于逻辑1,0V等价于逻辑0).这被称为TTL(晶体管一晶体管逻辑电平)信号系统,这是计算机处理器控制的设备内部各部分之间通信的标准技术。TTL电平信号对于计算机处理器控制的设备内部的数据传输是很理想的,首先计算机处理器控制的设备内部的数据传输对于电源的要求不高,热损耗也较低,另外TTL电平信号直接与集成电路连接而不需要价格昂贵的线路驱动器

功能函数

判断u8数组开头

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <string.h>
/////////////////////////
// 判断u8 arr开头是否为str //
////////////////////////
int u8cmp(u8 *arr, const char *str){
int i;
int len = strlen(str);
for ( i = 0; i < len; i++){
if( arr[i] != str[i]){
// arr shorter than str
if (arr[i] == '\0') return -1;
// not start with
return 0;
}
}
// arr start with str
return 1;
}

Author: Mrli

Link: https://nymrli.top/2019/10/15/玩玩Stm32/

Copyright: All articles in this blog are licensed under CC BY-NC-SA 3.0 unless stating additionally.

< PreviousPost
软件测试笔记
NextPost >
蒙特卡洛树搜索MCTS
CATALOG
  1. 1. 玩玩Stm32
    1. 1.1. 文件结构
      1. 1.1.1. 编写规范:
    2. 1.2. GPIO
      1. 1.2.1. 工作模式:
      2. 1.2.2. GPIO重要函数
        1. 1.2.2.1. 具体说明
      3. 1.2.3. demo : 跑马灯实验
        1. 1.2.3.1. 完整代码:
      4. 1.2.4. 操作IO口的三种方式:
    3. 1.3. 中断管理
      1. 1.3.1. 中断优先级设置步骤
    4. 1.4. 串口通信
      1. 1.4.1. 配置的一般步骤:
      2. 1.4.2. 正点原子提供的USART库:
    5. 1.5. 外部中断
      1. 1.5.1. 常用库函数
      2. 1.5.2. 配置的一般步骤
    6. 1.6. 附录:
      1. 1.6.1. u8、u16、Size_t是什么类型?
        1. 1.6.1.1. u8、u16
        2. 1.6.1.2. size_t
      2. 1.6.2. 电平相关知识
      3. 1.6.3. 功能函数