一. stm32F1硬件资源
STMicroelectronics的STM32F1系列是一系列广受欢迎的32位ARM Cortex-M微控制器(MCU)。这些单片机被广泛应用于嵌入式系统,因为它们具有高性能、低功耗、丰富的外设和丰富的开发工具生态系统。
1. 系统构架
主系统由以下部分构成:
● 四个驱动单元:
─ Cortex™-M3 内核 DCode 总线(D-bus),和系统总线(S-bus)
─ 通用 DMA1 和通用 DMA2
● 四个被动单元
─ 内部 SRAM
─ 内部闪存存储器
─ FSMC
─ AHB 到 APB 的桥(AHB2APBx),它连接所有的 APB 设备
这些都是通过一个多级的AHB总线构架相互连接的,如图所示:
具体参数为:
64或128 kb的Flash
20 KB的SRAM
嵌套矢量中断控制器(NVIC)
外部中断/事件控制器(EXTI)
时钟和启动
DMA
RTC(实时时钟)和备份寄存器
4个定时器和看门狗
2个I2C总线接口
通用同步/异步接收/发送(USART)
SPI接口
GPIO(通用输入/输出)
2个12位ADC
二. 基础设备开发重点
1.通用输入/输出(GPIO):
特点:GPIO引脚可以配置为输入或输出,用于连接和控制外部设备。
应用:用于连接传感器、LED、按钮和其他外部设备,实现输入和输出控制。
2. 专用控制器(TIM、ADC、RTC)
1)定时器:
特点:STM32单片机通常配备了多个定时器,包括通用定时器、高级定时器和基本定时器。这些定时器可用于生成定时、测量脉冲宽度、PWM控制等。
应用:用于控制电机速度、测量时间间隔、产生PWM信号等。
通用定时器是一个通过可编程预分频器驱动的16位自动装载计数器构成。
主要功能:
通用TIMx (TIM2、TIM3、TIM4和TIM5)定时器功能包括:
● 16位向上、向下、向上/向下自动装载计数器
● 16位可编程(可以实时修改)预分频器,计数器时钟频率的分频系数为1~65535之间的任意数值
● 4个独立通道:
─ 输入捕获
─ 输出比较
─ PWM 生成(边缘或中间对齐模式)
─ 单脉冲模式输出
● 使用外部信号控制定时器和定时器互连的同步电路
● 如下事件发生时产生中断/DMA:
─ 更新:计数器向上溢出/向下溢出,计数器初始化(通过软件或者内部/外部触发)
─ 触发事件(计数器启动、停止、初始化或者由内部/外部触发计数)
─ 输入捕获
─ 输出比较
─ 支持针对定位的增量(正交)编码器和霍尔传感器电路
─ 触发输入作为外部时钟或者按周期的电流管理
2) 串行通信接口UART
a.介绍
通用同步异步收发器(USART)提供了一种灵活的方法与使用工业标准NRZ异步串行数据格式的外部设备之间进行全双工数据交换。USART利用分数波特率发生器提供宽范围的波特率选择。
它支持同步单向通信和半双工单线通信,也支持LIN(局部互连网),智能卡协议和IrDA(红外数据组织)SIR ENDEC规范,以及调制解调器(CTS/RTS)操作。它还允许多处理器通信。
使用多缓冲器配置的DMA方式,可以实现高速数据通信。
b. USART功能描述
任何USART双向通信至少需要两个脚:接收数据输入(RX)和发送数据输出(TX)。
RX:接收数据串行输。通过过采样技术来区别数据和噪音,从而恢复数据。
TX:发送数据输出。当发送器被禁止时,输出引脚恢复到它的I/O端口配置。当发送器被激活,并且不发送数据时,TX引脚处于高电平。
● 总线在发送或接收前应处于空闲状态
● 一个起始位
● 一个数据字(8或9位),最低有效位在前
● 0.5,1.5,2个的停止位,由此表明数据帧的结束
● 使用分数波特率发生器 —— 12位整数和4位小数的表示方法。
● 一个状态寄存器(USART_SR)
● 数据寄存器(USART_DR)
● 一个波特率寄存器(USART_BRR),12位的整数和4位小数
UART示例:
void Init_Uart(void)
{
USART_InitTypeDef USART_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_InitStructure.USART_BaudRate = 115200;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_Init(USART1,&USART_InitStructure);
USART_Cmd(USART1,ENABLE);
}
void uart_send_byte(char ch)
{
USART_SendData(USART1,ch);
while(!USART_GetFlagStatus(USART1,USART_FLAG_TC));
}
char uart_recv_byte(void)
{
char ch;
while(RESET == USART_GetFlagStatus(USART1,USART_FLAG_RXNE));
ch = USART_ReceiveData(USART1);
return ch;
}
void uart_send_string(char *str)
{
while(*str)
{
uart_send_byte(*str);
str++;
}
}
int fputc(int ch, FILE *fp)
{
USART_SendData(USART1,ch);
while(!USART_GetFlagStatus(USART1,USART_FLAG_TC));
}
3)模数转换器(ADC):
特点:ADC允许将模拟信号转换为数字值,用于测量传感器数据等。
● 12-位分辨率
● 转换结束,注入转换结束和发生模拟看门狗事件时产生中断
● 单次和连续转换模式
● 从通道0到通道n的自动扫描模式
● 自校准
● 带内嵌数据一致的数据对齐
● 通道之间采样间隔可编程
● 规则转换和注入转换均有外部触发选项
应用:用于测量温度、湿度、光线等模拟信号,广泛应用于传感器接口。
示例:
void Init_ADC(ADC_TypeDef* ADCx)
{
ADC_InitTypeDef ADC_InitStructure;
ADC_DeInit(ADCx);
//ADC1 和 ADC2 工作在独立模式
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
//模数转换工作在扫描模式(多通道)还是单次(单通道)模式
ADC_InitStructure.ADC_ScanConvMode = ENABLE;
//模数转换工作在连续还是单次模式
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
//转换由软件而不是外部触发启动
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
// ADC 数据向左边对齐还是向右边对齐
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
//顺序进行规则转换的 ADC 通道的数目
ADC_InitStructure.ADC_NbrOfChannel = 1;
ADC_Init(ADCx, &ADC_InitStructure);
ADC_Cmd(ADCx, ENABLE);//使能ADC
//设置指定 ADC 的规则组通道,设置它们的转化顺序和采样时间 ADC_RegularChannelConfig(ADCx,ADC_Channel_1,1,ADC_SampleTime_55Cycles5);
ADC_ResetCalibration(ADC1); //使能复位校准
//等待复位校准结束
while(RESET == ADC_GetResetCalibrationStatus(ADC1));
ADC_StartCalibration(ADCx);//开始校准
while(RESET == ADC_GetCalibrationStatus(ADCx));//等待校准完成
//使能或者失能 ADCx 软件启动注入组转换功能
ADC_SoftwareStartConvCmd(ADCx,ENABLE);
}
4)PWM控制器:
特点:PWM(脉冲宽度调制)控制器用于生成PWM信号,可用于控制电机速度、LED亮度等。
应用:用于电机控制、LED灯控制、音频处理等。
示例:
void Init_TIM3(void)
{
TIM_TimeBaseInitTypeDef TIM_BaseInitStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
//TIM3的基本配置
TIM_BaseInitStructure.TIM_Prescaler = 720;//预分频
TIM_BaseInitStructure.TIM_Period = 2000;//ARR 计数周期
TIM_BaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;//向上计数
TIM_BaseInitStructure.TIM_Clockpision = TIM_CKD_p1;
TIM_TimeBaseInit(TIM3, &TIM_BaseInitStructure);//初始化TIM3
//配置TIM3的通道1输出PWM脉冲
//TIM 脉冲宽度调制模式 1
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
//Specifies the TIM Output Compare state
TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable; TIM_OCInitStructure.TIM_Pulse = 0;//设置装入捕获比较寄存器的脉冲值 CCR
//TIM 输出比较极性:高 即周期内低于TIM_Pulse这个阈值的时间,都是高 //电平,其他时间都是低;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC1Init(TIM3,&TIM_OCInitStructure);//初始化TIM3的Channel1
TIM_OC2Init(TIM3,&TIM_OCInitStructure);//初始化TIM3的Channel2
TIM_OC3Init(TIM3,&TIM_OCInitStructure);//初始化TIM3的Channel3
TIM_OC4Init(TIM3,&TIM_OCInitStructure);//初始化TIM3的Channel4
//Enables or disables the TIMx peripheral Preload register on CCRx.
TIM_OC1PreloadConfig(TIM3,TIM_OCPreload_Enable);
TIM_OC2PreloadConfig(TIM3,TIM_OCPreload_Enable);
TIM_OC3PreloadConfig(TIM3,TIM_OCPreload_Enable);
TIM_OC4PreloadConfig(TIM3,TIM_OCPreload_Enable);
//Enables or disables TIMx peripheral Preload register on ARR.
TIM_ARRPreloadConfig(TIM3,ENABLE);
// Enables or disables the TIM peripheral Main Outputs.
TIM_CtrlPWMOutputs(TIM3,ENABLE);
TIM_Cmd(TIM3,ENABLE);//使能TIM3
}
3.时钟配置
三种不同的时钟源可被用来驱动系统时钟(SYSCLK):
● HSI振荡器时钟
● HSE振荡器时钟
● PLL时钟
这些设备有以下2种二级时钟源:
● 40kHz低速内部RC,可以用于驱动独立看门狗和通过程序选择驱动RTC。RTC用于从停机/待机模式下自动唤醒系统。
● 32.768kHz低速外部晶体也可用来通过程序选择驱动RTC(RTCCLK)。
当不被使用时,任一个时钟源都可被独立地启动或关闭,由此优化系统功耗。时钟树
4.通信时序(UART、I2C、SPI)
1)串口时序
串口通信通常需要配置参数(波特率、数据位、起始位、停止位、奇偶校验位)
2)I2C时序
开始(S)和结束(P)标志:
开始信号:处理器让SCL时钟保持高电平,然后让SDA数据信号由高变低就表示一个开始信号。同时IIC总线上的设备检测到这个开始信号它就知道处理器要发送数据了。
停止信号:处理器让SCL时钟保持高电平,然后让SDA数据信号由低变高就表示一个停止信号。同时IIC总线上的设备检测到这个停止信号它就知道处理器已经结束了数据传输,我们就可以各忙各个的了,如休眠等。
通信:
开始标志(S)发出后,主设备会传送一个7 位的Slave 地址,并且后面跟着一个第8位,称为Read/Write 位。R/W 位表示主设备是在接受从设备的数据还是在向其写数据。然后,主设备释放SDA 线,等待从设备的应答信号(ACK)。每个字节的传输都要跟随有一个应答位。应答产生时(既把SDA拉低),从设备将SDA 线拉低并且在SCL 为高电平时保持低。数据传输总是以停止标志(P)结束,然后释放通信线路。然而,主设备也可以产生重复的开始信号去操作另一台从设备,而不发出结束标志。综上可知,所有的SDA 信号变化都要在SCL 时钟为低电平时进行,除了开始和结束标志。
(3)SPI时序
SPI_CR寄存器的CPOL和CPHA位,能够组合成四种可能的时序关系。CPOL(时钟极性)位控制在没有数据传输时时钟的空闲状态电平,此位对主模式和从模式下的设备都有效。如果CPOL被清’0’,SCK引脚在空闲状态保持低电平;如果CPOL被置’1’,SCK引脚在空闲状态保持高电平。
如果CPHA(时钟相位)位被置’1’,SCK时钟的第二个边沿(CPOL位为0时就是下降沿,CPOL位为1时就是上升沿)进行数据位的采样,数据在第二个时钟边沿被锁存。如果CPHA位被清’0’,SCK时钟的第一边沿(CPOL位为0时就是下降沿,CPOL位为1时就是上升沿)进行数据位采样,数据在第一个时钟边沿被锁存。
CPOL时钟极性和CPHA时钟相位的组合选择数据捕捉的时钟边沿。
图208显示了SPI传输的4种CPHA和CPOL位组合。此图可以解释为主设备和从设备的SCK脚、MISO脚、MOSI脚直接连接的主或从时序图。
注意:
1. 在改变 CPOL/CPHA 位之前,必须清除 SPE 位将 SPI 禁止。
2. 主和从必须配置成相同的时序模式。
3. SCK 的空闲状态必须和 SPI_CR1 寄存器指定的极性一致 (CPOL 为 1 时,空闲时应上拉 SCK 为高电平; CPOL 为 0 时,空闲时应下拉 SCK 为低电平 ) 。
4. 数据帧格式 (8 位或 16 位 ) 由 SPI_CR1 寄存器的 DFF 位选择,并且决定发送 / 接收的数据长度。
5.中断开发
STM32F103xx性能线嵌入了一个嵌套的矢量中断控制器,能够处理多达43个可屏蔽中断通道(不包括Cortex-M3的16个中断线)和16个优先级级别。
1)常见中断类型:
EXTI中断:主要由外设触发的中断
ADC中断:主要由ADC触发的中断
TIM中断:主要由定时器触发的中断
USART中断:主要由串口触发的中断
DMA全局中断:主要由DMA触发的中断
2)TIM2中断为例
void Init_NVIC(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
void Init_TIM2(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_Period = 1000-1;
TIM_TimeBaseInitStructure.TIM_Prescaler = 720-1;
TIM_TimeBaseInitStructure.TIM_Clockpision = TIM_CKD_p1;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
TIM_Cmd(TIM2,ENABLE);
}
void TIM2_IRQHandler(void)
{
//中断处理
TIM_ClearITPendingBit(TIM2,TIM_IT_Update);//清中断标志
}
三. 开发方式介绍
1.标准库开发
1)开发环境搭建
a.下载安装keil MDK-ARM集成开发环境
b.导入芯片支持包
c.创建新项目
选择合适的设备型号
选择外设驱动
d.编程
2)点灯示例
void Init_GPIO(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
}
void led_on(void)
{
GPIO_SetBits(GPIOA,GPIO_Pin_5); //点亮LED
}
void led_off(void)
{
GPIO_ResetBits (GPIOA,GPIO_Pin_5); //熄灭LED
}
2.stm32CubeMx工具开发
1)开发环境搭建
a.官网下载JRE和stm32CubeMx并安装
b.stm32CubeMx库安装
c.创建工程
d.生成keil工程并添加自己的功能代码
2)点灯示例