关于单片机

8位单片机

单片机是一种集成电路芯片,是采用超大规模集成电路技术把具有数据处理能力的中央处理器、存储器、输入输出端口、中断系统和定时器等功能集成到一块硅片上构成的小而完善的微型计算机系统。

1. MCS-51系列

Intel公司单片机系列总称。

  • 基础型:8031,8051,8751
  • 增强型:8032,8052,8752

2. AT89系列

ATMEL公司将Flash与8051内核结合,推出:

  • AT89C5X系列:AT89C51,AT89C52(增强型)
  • AT89S5X系列:AT89S51,AT89S52(增强型)

3. STC系列

宏晶科技(STC)自主研发。

4. AVR系列

ATMEL公司研发的增强型内置Flash的RISC高速8位单片机。

嵌入式:以应用为中心,以计算机技术为基础,适用于对体积、功耗、性能等方面有严格要求的计算机系统

ARM内核架构

ARM,一家英国公司,主设计芯片的IP内核。

ARM内核架构:

  1. 早期:ARM7,ARM9,ARM11
  2. 目前:
  • ① cortex A 系列:面向高端智能产品(搭载操作系统)
  • ② cortex R 系列:面向实时性要求高的产品(航空航天,汽车)
  • ③ cortex M 系列:面向成本敏感型产品

STM32开发方式

  1. 函数库开发方式
  2. 寄存器开发方式

单片机最小系统

  1. 引脚基本分类
  • 电源引脚
  • 晶振引脚
  • 复位引脚
  • 控制引脚
  • 输入输出引脚
  1. 电源电路
  2. 晶振电路
  3. 复位电路
  4. 外围电路

C语言

1. 位操作

运算符含义
&按位与
\按位或
^按位异或
~取反
<<左移
>>右移

2. 宏定义

define是C语言中预处理命令,用于宏定义,提高代码可读#性

格式:

#define 标识符 字符串
字符串可以是常数、表达式、格式串等

3. 条件编译

当满足条件时对一组语句进行编译,条件不满足时编译另一组语句

#ifdef 标识符
    程序段1
#else
     程序段2
#endif

4. 变量声明

extern可置于变量或函数前,表示变量或者函数的定义在别的文件中,提示编译器在遇到该变量或函数是去其他文件中寻找其定义。extern申明变量可以多次,但定义只有一次

5. 类型别名

typedef定义一种类型的别名,并不是简单的宏替换,可以用作同时声明指针型的多个对象。

typedef unsigned char uint8_t;
typedef unsigned short int uint16_t;
typedef unsigned int uint32_t;

6. 结构体

在结构体声明的时候可以定义变量,也可以声明之后再定义,格式:

Struct 结构体名 结构体变量列表;

Struct 结构体名 {
    变量1;
    变量2;
    ...
}变量名列表;

7. 关键字static

  • Static定义的局部变量,存储在静态存储区
  • 在函数调用结束后,不会被释放,它的值会一直保留下来,具有记忆功能

工程模板

以STM32F411CEU6核心板为例

固件库下载

ST官网固件库下载:https://www.st.com/en/embedded-software/stm32-standard-peripheral-libraries.html

选择F4进入:

点击进入,进行邮箱验证,正常下载即可:

下载解压后文件结构如下所示:

工程目录结构

├─CORE
│      core_cm4.h
│      core_cmFunc.h
│      core_cmInstr.h
│      core_cmSimd.h
│      startup_stm32f40_41xxx.s
│      startup_stm32f411xe.s
│  
├─FWLIB
│  ├─inc
│  │      misc.h
│  │      stm32f4xx_adc.h
│  │      stm32f4xx_can.h
│  │      stm32f4xx_cec.h
│  │      stm32f4xx_crc.h
│  │      stm32f4xx_cryp.h
│  │      stm32f4xx_dac.h
│  │      stm32f4xx_dbgmcu.h
│  │      stm32f4xx_dcmi.h
│  │      stm32f4xx_dfsdm.h
│  │      stm32f4xx_dma.h
│  │      stm32f4xx_dma2d.h
│  │      stm32f4xx_dsi.h
│  │      stm32f4xx_exti.h
│  │      stm32f4xx_flash.h
│  │      stm32f4xx_flash_ramfunc.h
│  │      stm32f4xx_fmc.h
│  │      stm32f4xx_fmpi2c.h
│  │      stm32f4xx_fsmc.h
│  │      stm32f4xx_gpio.h
│  │      stm32f4xx_hash.h
│  │      stm32f4xx_i2c.h
│  │      stm32f4xx_iwdg.h
│  │      stm32f4xx_lptim.h
│  │      stm32f4xx_ltdc.h
│  │      stm32f4xx_pwr.h
│  │      stm32f4xx_qspi.h
│  │      stm32f4xx_rcc.h
│  │      stm32f4xx_rng.h
│  │      stm32f4xx_rtc.h
│  │      stm32f4xx_sai.h
│  │      stm32f4xx_sdio.h
│  │      stm32f4xx_spdifrx.h
│  │      stm32f4xx_spi.h
│  │      stm32f4xx_syscfg.h
│  │      stm32f4xx_tim.h
│  │      stm32f4xx_usart.h
│  │      stm32f4xx_wwdg.h
│  │
│  └─src
│          misc.c
│          stm32f4xx_adc.c
│          stm32f4xx_can.c
│          stm32f4xx_cec.c
│          stm32f4xx_crc.c
│          stm32f4xx_cryp.c
│          stm32f4xx_cryp_aes.c
│          stm32f4xx_cryp_des.c
│          stm32f4xx_cryp_tdes.c
│          stm32f4xx_dac.c
│          stm32f4xx_dbgmcu.c
│          stm32f4xx_dcmi.c
│          stm32f4xx_dfsdm.c
│          stm32f4xx_dma.c
│          stm32f4xx_dma2d.c
│          stm32f4xx_dsi.c
│          stm32f4xx_exti.c
│          stm32f4xx_flash.c
│          stm32f4xx_flash_ramfunc.c
│          stm32f4xx_fmc.c
│          stm32f4xx_fmpi2c.c
│          stm32f4xx_fsmc.c
│          stm32f4xx_gpio.c
│          stm32f4xx_hash.c
│          stm32f4xx_hash_md5.c
│          stm32f4xx_hash_sha1.c
│          stm32f4xx_i2c.c
│          stm32f4xx_iwdg.c
│          stm32f4xx_lptim.c
│          stm32f4xx_ltdc.c
│          stm32f4xx_pwr.c
│          stm32f4xx_qspi.c
│          stm32f4xx_rcc.c
│          stm32f4xx_rng.c
│          stm32f4xx_rtc.c
│          stm32f4xx_sai.c
│          stm32f4xx_sdio.c
│          stm32f4xx_spdifrx.c
│          stm32f4xx_spi.c
│          stm32f4xx_syscfg.c
│          stm32f4xx_tim.c
│          stm32f4xx_usart.c
│          stm32f4xx_wwdg.c
│
├─HARDWARE
├─OBJ
├─SYSTEM
│      stm32f4xx.h
│      system_stm32f4xx.c
│      system_stm32f4xx.h
│
└─USER
    │  main.c
    │  stm32f4xx_conf.h
    │  stm32f4xx_it.c
    │  stm32f4xx_it.h
    │  Template.uvguix.22515
    │  Template.uvoptx
    │  Template.uvprojx
    │
    ├─DebugConfig
    │      Target_1_STM32F411CEUx.dbgconf
    │      Template_STM32F411CEUx.dbgconf
    │
    ├─Listings
    │      startup_stm32f411xe.lst
    │      Template.map
    │
    └─Objects
            main.crf
            main.d
            main.o
            misc.crf
            misc.d
            misc.o
            startup_stm32f411xe.d
            startup_stm32f411xe.o
            stm32f4xx_gpio.crf
            stm32f4xx_gpio.d
            stm32f4xx_gpio.o
            stm32f4xx_it.crf
            stm32f4xx_it.d
            stm32f4xx_it.o
            stm32f4xx_rcc.crf
            stm32f4xx_rcc.d
            stm32f4xx_rcc.o
            stm32f4xx_usart.crf
            stm32f4xx_usart.d
            stm32f4xx_usart.o
            system_stm32f4xx.crf
            system_stm32f4xx.d
            system_stm32f4xx.o
            Template.axf
            Template.build_log.htm
            Template.htm
            Template.lnp
            Template.sct
            Template_Template.dep

1. 创建工程文件夹

新建工程模板文件夹Template,在该目录下创建以下文件夹:

文件夹用途
CORE控制器软件接口标准文件
FWLIB对应外设模块代码(inc src)
HARDWARE用户的外设功能模块
OBJ编译产生的中间文件
SYSTEM系统相关代码
USER自定义代码(main.c)

2. 文件拷贝

将固件库代码拷贝到对应工程文件夹下:

  • FWLIB

    Libraries\STM32F4xx_StdPeriph_Driver\inc 库头文件

    Libraries\STM32F4xx_StdPeriph_Driver\inc 库源文件

  • USER

    Project\STM32F4xx_StdPeriph_Templates\main.c

    Project\STM32F4xx_StdPeriph_Templates\stm32f4xx_it.h 中断函数头文件

    Project\STM32F4xx_StdPeriph_Templates\stm32f4xx_it.c 中断函数文件

    Project\STM32F4xx_StdPeriph_Templates\stm32f4xx_conf.h 配置文件

  • CORE

    Libraries\CMSIS\Device\ST\STM32F4xx\Source\Templates\arm\startup_stm32f411xe.s

    Libraries\CMSIS\Include\core_cm4.h

    Libraries\CMSIS\Include\core_cmSimd.h

    Libraries\CMSIS\Include\core_cmFunc.h

    Libraries\CMSIS\Include\core_cmInstr.h

  • SYSTEM

    Libraries\CMSIS\Device\ST\STM32F4xx\Include\stm32f4xx.h

    Libraries\CMSIS\Device\ST\STM32F4xx\Include\system_stm32f4xx.h

    Libraries\CMSIS\Device\ST\STM32F4xx\Source\Templates\system_stm32f4xx.c

目录结构:

├─CORE
│      core_cm4.h
│      core_cmFunc.h
│      core_cmInstr.h
│      core_cmSimd.h
│      startup_stm32f40_41xxx.s
│      startup_stm32f411xe.s
│  
├─FWLIB
│  ├─inc
│  │      misc.h
│  │      stm32f4xx_adc.h
│  │      stm32f4xx_can.h
│  │      stm32f4xx_cec.h
│  │      stm32f4xx_crc.h
│  │      stm32f4xx_cryp.h
│  │      stm32f4xx_dac.h
│  │      stm32f4xx_dbgmcu.h
│  │      stm32f4xx_dcmi.h
│  │      stm32f4xx_dfsdm.h
│  │      stm32f4xx_dma.h
│  │      stm32f4xx_dma2d.h
│  │      stm32f4xx_dsi.h
│  │      stm32f4xx_exti.h
│  │      stm32f4xx_flash.h
│  │      stm32f4xx_flash_ramfunc.h
│  │      stm32f4xx_fmc.h
│  │      stm32f4xx_fmpi2c.h
│  │      stm32f4xx_fsmc.h
│  │      stm32f4xx_gpio.h
│  │      stm32f4xx_hash.h
│  │      stm32f4xx_i2c.h
│  │      stm32f4xx_iwdg.h
│  │      stm32f4xx_lptim.h
│  │      stm32f4xx_ltdc.h
│  │      stm32f4xx_pwr.h
│  │      stm32f4xx_qspi.h
│  │      stm32f4xx_rcc.h
│  │      stm32f4xx_rng.h
│  │      stm32f4xx_rtc.h
│  │      stm32f4xx_sai.h
│  │      stm32f4xx_sdio.h
│  │      stm32f4xx_spdifrx.h
│  │      stm32f4xx_spi.h
│  │      stm32f4xx_syscfg.h
│  │      stm32f4xx_tim.h
│  │      stm32f4xx_usart.h
│  │      stm32f4xx_wwdg.h
│  │
│  └─src
│          misc.c
│          stm32f4xx_adc.c
│          stm32f4xx_can.c
│          stm32f4xx_cec.c
│          stm32f4xx_crc.c
│          stm32f4xx_cryp.c
│          stm32f4xx_cryp_aes.c
│          stm32f4xx_cryp_des.c
│          stm32f4xx_cryp_tdes.c
│          stm32f4xx_dac.c
│          stm32f4xx_dbgmcu.c
│          stm32f4xx_dcmi.c
│          stm32f4xx_dfsdm.c
│          stm32f4xx_dma.c
│          stm32f4xx_dma2d.c
│          stm32f4xx_dsi.c
│          stm32f4xx_exti.c
│          stm32f4xx_flash.c
│          stm32f4xx_flash_ramfunc.c
│          stm32f4xx_fmc.c
│          stm32f4xx_fmpi2c.c
│          stm32f4xx_fsmc.c
│          stm32f4xx_gpio.c
│          stm32f4xx_hash.c
│          stm32f4xx_hash_md5.c
│          stm32f4xx_hash_sha1.c
│          stm32f4xx_i2c.c
│          stm32f4xx_iwdg.c
│          stm32f4xx_lptim.c
│          stm32f4xx_ltdc.c
│          stm32f4xx_pwr.c
│          stm32f4xx_qspi.c
│          stm32f4xx_rcc.c
│          stm32f4xx_rng.c
│          stm32f4xx_rtc.c
│          stm32f4xx_sai.c
│          stm32f4xx_sdio.c
│          stm32f4xx_spdifrx.c
│          stm32f4xx_spi.c
│          stm32f4xx_syscfg.c
│          stm32f4xx_tim.c
│          stm32f4xx_usart.c
│          stm32f4xx_wwdg.c
│
├─HARDWARE
├─OBJ
├─SYSTEM
│      stm32f4xx.h
│      system_stm32f4xx.c
│      system_stm32f4xx.h
│
└─USER
    │  main.c
    │  stm32f4xx_conf.h
    │  stm32f4xx_it.c
    │  stm32f4xx_it.h
    │  Template.uvguix.22515
    │  Template.uvoptx
    │  Template.uvprojx
    │
    ├─DebugConfig
    │      Target_1_STM32F411CEUx.dbgconf
    │      Template_STM32F411CEUx.dbgconf
    │
    ├─Listings
    │      startup_stm32f411xe.lst
    │      Template.map
    │
    └─Objects
            main.crf
            main.d
            main.o
            misc.crf
            misc.d
            misc.o
            startup_stm32f411xe.d
            startup_stm32f411xe.o
            stm32f4xx_gpio.crf
            stm32f4xx_gpio.d
            stm32f4xx_gpio.o
            stm32f4xx_it.crf
            stm32f4xx_it.d
            stm32f4xx_it.o
            stm32f4xx_rcc.crf
            stm32f4xx_rcc.d
            stm32f4xx_rcc.o
            stm32f4xx_usart.crf
            stm32f4xx_usart.d
            stm32f4xx_usart.o
            system_stm32f4xx.crf
            system_stm32f4xx.d
            system_stm32f4xx.o
            Template.axf
            Template.build_log.htm
            Template.htm
            Template.lnp
            Template.sct
            Template_Template.dep

工程配置

1. 创建工程

打开keil5,创建新的工程Template,保存到USER文件夹下,并选择对应的芯片型号

接下来将模板中的文件添加到工程中去:

2. 配置输出文件

设置生成HEX文件,输出位置为OBJ文件夹

3. 配置宏

STM32F411xE,USE_STDPERIPH_DRIVER

4. 添加头文件路径

编译

首先将Target标签下的ARM complier改为版本5

编译出现一个错误

main.h那行代码删除,重新编译,出现警告和错误:

将触发警告的代码注释掉

重新编译通过:

资料打包:

[btn href="https://pan.ztongyang.cn/s/3jnhO" type=" orange" ico=""]点击下载工程模板[/btn]


时钟

时钟树

时钟源

  1. LSI

    低速内部时钟,由内部RC振荡器产生,频率32kHz,为独立看门狗提供时钟,对时钟精度要求不是很高。也可为RTC时钟来源。

  2. LSE

    低速外部时钟,频率32.768kHz,RTC

  3. HSE

    高速精确的外部时钟,可接石英/陶瓷谐振器,或接外部时钟源,频率范围:4MHz~26MHz

  4. HSI

    内部高速时钟,16MHz,可作为系统时钟或用于PLL时钟输入

  5. PLL

    锁相环倍频输出,F4有两个PLL:

    • 主PLL由HSE或HSI提供时钟信号 ,具有两个不同的输出时钟:

      • ① 用于生成高速的系统时钟,最高168MHz
      • ② 用于生成USB OTG FS时钟(48MHz),随机数发生器的时钟和SDIO时钟
    • 专用PLL,用于生成精确时钟,在I2S接口实现高品质音频性能

系统时钟

三个来源:

  1. HSI振荡器时钟
  2. HSE振荡器时钟
  3. PLL时钟

时钟信号输出

  1. MCO1

    PA8引脚,可配置预分频器(1~5)向MCO1引脚PA8输出4个不同时钟源:

    • HIS
    • LSE
    • HSE
    • PLL
  2. MCO2

    PC9引脚,可配置预分频器(1~5)向MCO2引脚PC9输出4个不同时钟源:

    • HSE
    • PLL
    • SYSCLK
    • PLLI2S
MCO最大输出时钟不超过100MHz

串口使用

STM32常用的串口相关寄存器

  • USART_SR 状态寄存器
  • USART_DR 数据寄存器
  • USART_BRR 波特率寄存器
  • USART_CRx 控制寄存器

STM32串口操作相关函数

序号函数功能
1void USART_Init();串口初始化
2void USART_Cmd();使能串口
3void USART_ITConfig();使能相关中断
4void USART_SendData();发送数据到串口,DR
5uint16_t USART ReceiveData();接收数据,从DR读取接收到的数据
6FlagStatus USART_GetFlagStatus();获取状态标志位
7void USART_ClearFlag();清除状态标志位
8ITStatus USART_GetITStatus();获取中断标志位
9void USART_ClearITPendingBit();清除中断状态标志位

串口初始化:

  • 波特率
  • 数据字长
  • 奇偶校验
  • 硬件流控
  • 收发使能

串口配置的一般步骤

  1. 串口时钟使能,GPIO时钟使能:RCC_APB2PeriphClockCmd();
  2. 串口复位: USART_DeInit();(非必须)
  3. GPIO端口模式设置:GPIO_Init();
  4. 串口参数初始化:USART_Init();
  5. 开启终端并且初始化NVIC(优先级管理),需开启中断才执行此步骤

    NVIC_Init();,USART_ITConfig();

  6. 使能串口: USART_Cmd();
  7. 编写中断处理函数: USARTx_IRQHandler();
  8. 串口数据收发:

    void USART_SendData();发送数据到串口

    uint16_t USART_ReceiveData();接收数据,从DR读取接收到的数据

  9. 串口传输状态获取

    FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG);
    void USART_ClearFlag(USART_TypeDef* USARTx, uint16_t USART_FLAG);

示例代码

#include "stm32f10x.h"

 
void My_USART1_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStrue;                             //GPIO初始化结构体
    USART_InitTypeDef USART_InitStrue;                            //串口初始化结构体
    NVIC_InitTypeDef NVIC_InitStrue;                            //NVIC初始化结构体

    // 1. 串口、GPIO时钟使能
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

    // 2. GPIO端口模式设置
    GPIO_InitStrue.GPIO_Mode     =     GPIO_Mode_AF_PP;             // 推挽复用输出
    GPIO_InitStrue.GPIO_Pin         =     GPIO_Pin_9;
    GPIO_InitStrue.GPIO_Speed    =    GPIO_Speed_10MHz;
    GPIO_Init(GPIOA,&GPIO_InitStrue);


    GPIO_InitStrue.GPIO_Mode     =     GPIO_Mode_IN_FLOATING;        // 浮空输入
    GPIO_InitStrue.GPIO_Pin         =     GPIO_Pin_10;
    GPIO_InitStrue.GPIO_Speed    =     GPIO_Speed_10MHz;
    GPIO_Init(GPIOA,&GPIO_InitStrue);


    // 3. 串口初始化
    USART_InitStrue.USART_BaudRate                =     115200;                                //波特率
    USART_InitStrue.USART_HardwareFlowControl    =    USART_HardwareFlowControl_None;        //不使用硬件流
    USART_InitStrue.USART_Mode                    =     USART_Mode_Rx | USART_Mode_Tx;        //发送、接收使能
    USART_InitStrue.USART_Parity                =    USART_Parity_No;                    //奇偶校验
    USART_InitStrue.USART_StopBits                =    USART_StopBits_1;                    //1个停止位
    USART_InitStrue.USART_WordLength            =     USART_WordLength_8b;                //字长8
    USART_Init(USART1,&USART_InitStrue);

    // 4. 使能串口
    USART_Cmd(USART1,ENABLE);
    USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);                            //串口1接收中断
    NVIC_InitStrue.NVIC_IRQChannel                         =     USART1_IRQn;    //通道
    NVIC_InitStrue.NVIC_IRQChannelCmd                    =    ENABLE;            //开启中断通道
    NVIC_InitStrue.NVIC_IRQChannelPreemptionPriority     =     1;                //抢占优先级
    NVIC_InitStrue.NVIC_IRQChannelSubPriority            =     1;                //子优先级
    NVIC_Init(&NVIC_InitStrue);

}
 
// 中断服务函数
void USART1_IRQHandler(void)
{
    u8 data;
    if(USART_GetITStatus(USART1,USART_IT_RXNE))                    //中断判断
    {
        data = USART_ReceiveData(USART1);                        //读取串口1收到的数据
        USART_SendData(USART1,data);                            //发送收到的数据
    }
}

int main(void)
{
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);                //系统中断优先级分组
    My_USART1_Init();
    while(1);