个人工作上的关系,需要做一款温度控制风扇速度的控制器,还需要能够看到温度和PWM的值。于是我用这个不熟悉的 STM32F103 试试,顺便把 PWM 和 SPI 也了解一番。
一开始当然也是跌跌撞撞,搞了很久才弄清楚。这篇笔记记录怎么做好的过程。
实验的过程是以正点原子 STM32F103 nano开发板和他附上的练习程式开始。
参考 NANO 的程式
依照正点原子的教材,跑了一下 nano 程式,执行了 OK!原来的程式里面 PWM 用 TIM3 的 channel_1 控制 PC6 的 LED 闪烁。SPI 是用 SPI2 控制 W25Q16 进行读写。
由于 PWM 和 SPI2 都被开发板占有,我选了另外一组 TIM2_CH2 和 SPI1 做我的控制件。作业如下:
PWM
从原来的程式,可以知道要调整那么多开关,以下是 nano 的 测试程式内容:
void TIM3_PWM_Init(u16 arr,u16 psc)
{
RCC->APB1ENR|=1<<1; //TIM3 时钟使能
RCC->APB2ENR|=1<<4; //使能 PORTC 时钟
GPIOC->CRL&=0XF0FFFFFF;//PC6 输出
GPIOC->CRL|=0X0B000000; //复用功能输出
RCC->APB2ENR|=1<<0; //使能 AFIO 时钟
AFIO->MAPR&=0XFFFFF3FF; //清除 MAPR 的[11:10]
AFIO->MAPR|=3<<10; //部分重映像,TIM3_CH1->PC6
TIM3->ARR=arr; //设定计数器自动重装值
TIM3->PSC=psc; //预分频器不分频
TIM3->CCMR1|=7<<4; //CH1 PWM2 模式
TIM3->CCMR1|=1<<3; //CH1 预装载使能
TIM3->CCER|=1<<0; //OC1 输出使能
TIM3->CR1=0x0080; //ARPE 使能
TIM3->CR1|=0x01; //使能定时器 3
}
这里直接写正确的进行方式,不讲其他的故事了
设定 TIMx_CHx 有下面几个部分:
1. 查看 APIO 的資料,把 TIM2 的 “REMAP” 里面对应的 GPIO pin 脚选定。
参考 nano 的预留 IO 脚,我们选择 TIM2_CH2, 脚位是 PA1. 这个时候 要记得 APIO_MAPR 的 TIM2_REMAP 要选择 “00" 或 ”10“.
2. 进RCC,要把 TIM2 的开关打开
这个是 RCC->APB1ENR 的内容,可以看到 TIM3 bit_1, TIM2 是在 bit_0. 所以,还要把 AFIO 输出的开关 打开,改成
RCC->APB1ENR|=1<<0; //TIM2 时钟使能
RCC->APB2ENR|=1<<0; //select AFIO output
4. 把 GPIO 的相关开关打开
这个部分要很熟悉才是, 但是记得 用 0xB 设定 pin 脚输出模式:
RCC->APB2ENR|=1<<2; //PORTA
GPIOA->CRL&=0XFFFFFF0F; //PA1
GPIOA->CRL|=0X000000B0; //'1011 to PA1
5. 把 APIO 的开关打开
主要就是 复用重映射和调试I/O配置寄存器(AFIO_MAPR) 的设定
AFIO->MAPR&=0XFFFFFCFF; // '1100' to clear REMAPR[9:8] TIM2
6. 把 TIM2 的相关开关设定好
这个部分就是抄袭原来的范例,没有变更:
TIM2->ARR=arr; //set frequency to TIM2
TIM2->PSC=psc; //psc
TIM2->CR1=0x0080; //ARPE
TIM2->CR1|=0x01; //3
7. 把 CH2 的相关开关设定好
这里要特变注意到的是 CH1,CH2 在 TIMx_CCMR1 ;CH3,CH4 在 TIMx_CCMR2. 两个不同寄存器里面。检查寄存器的结构,可以看出 bit 0-7 一组(CH1, CH3)和 bit 8~15(CH2, CH4);
因为我们选的是 CH2, 所以设定在 CCMR1.
CCER 没有变化,直接拿过来。
//----TIM2_CH2 setting--
TIM2->CCMR1|=7<<12; //CH2 PWM2CH2->
TIM2->CCMR1|=1<<11; //CH2 PWM2CH2->
TIM2->CCER|=1<<4; //CC2E_OC2
8. 最后一个很重要 CCRx
这一段資料在 pwm.h 的 Define 里面。就是 每一个CH 都有自己的 CCR
CH1 对 CCR1,CH2 对 CCR2,CH3 对 CCR3,CH4 对 CCR4.下面示范了几个不同写法;
//TIM3->CCR1 LED6
#define LED6_PWM_VAL TIM3->CCR1
//TIM3->CCR2 LED7
#define PC7_PWM_VAL TIM3->CCR2
//TIM2->CCR3 PB10
#define PB10_PWM_VAL TIM2->CCR3
//TIM2->CCR2 PA1
#define PA1_PWM_VAL TIM2->CCR2
如果对直接修改的过程没有信心, 可以先改一个 TIM3_CH2 的过程测试(PC7 LED 明暗)。多验证几种,多改几次会有信心些。
以下是修改完成的 PWM 程式
pwm.c
//
//change it to TIM2 CH2-PA1
//arr the valeu to auto-reload
//pscPrescaler value--f CK_PSC /(PSC[15:0]+1)
void TIM2_PWM_Init(u16 arr,u16 psc)
{ //--------GPIOB-- setting ------------------------
RCC->APB2ENR|=1<<2; //PORTA
GPIOA->CRL&=0XFFFFFF0F; //PA1
GPIOA->CRL|=0X000000B0; //'1011 to PA1
//---TIM2 setting
RCC->APB1ENR|=1<<0; //TIM2
RCC->APB2ENR|=1<<0; //select AFIO output
AFIO->MAPR&=0XFFFFFCFF; //清'1100' to clear REMAPR[9:8] TIM2
//---TIM2-CH2 setting
// AFIO->MAPR|=0xE<<8; //TIM2_REMAP10=10,->'1110'
TIM2->ARR=arr; //set frequency to TIM2
TIM2->PSC=psc; //psc
TIM2->CR1=0x0080; //ARPE
TIM2->CR1|=0x01; //3
//----TIM2_CH2 setting--
TIM2->CCMR1|=7<<12; //CH2 PWM2CH2->
TIM2->CCMR1|=1<<11; //CH2 PWM2CH2->
TIM2->CCER|=1<<4; //CC2E_OC2
}
pwm.h
#ifndef __PWM_H
#define __PWM_H
#include "sys.h"
//
//try a new PWM by TIM2
//
//TIM3->CCR1 LED6
#define LED6_PWM_VAL TIM3->CCR1
//TIM3->CCR1 LED6
#define PA7_PWM_VAL TIM3->CCR2
//TIM2->CCR3 PB10
#define PB10_PWM_VAL TIM2->CCR3
//TIM2->CCR2 PA1
#define PA1_PWM_VAL TIM2->CCR2
void TIM3_PWM_Init(u16 arr,u16 psc);
void TIM2_PWM_Init(u16 arr,u16 psc);
#endif
pwm.h 里面保留了 nano 开发板原来的 PC6 亮度调变程式;目的在视觉观察程式是否正常用的。
SPI
SPI 的原件很多,应用也很广,在网上也能够取得许多不同的程式。这次试验的目的在用 SPI1 接收 MAX6675 的讯号。这里先调整 SPI。
下面是 nano 板的程式,选的是 SPI2.
spi2.c
//-------------------------------------------------
void SPI2_Init(void)
{
RCC->APB2ENR|=1<<3; //PORTB 时钟使能
RCC->APB1ENR|=1<<14; //SPI2 时钟使能
//这里只针对 SPI 口初始化
GPIOB->CRH&=0X000FFFFF;
GPIOB->CRH|=0XBBB00000; //PB13/14/15 复用
GPIOB->ODR|=0X7<<13; //PB13/14/15 上拉
SPI2->CR1|=0<<10; //全双工模式
SPI2->CR1|=1<<9; //软件 nss 管理
SPI2->CR1|=1<<8;
SPI2->CR1|=1<<2; //SPI 主机
SPI2->CR1|=0<<11; //8bit 数据格式
SPI2->CR1|=1<<1; //空闲模式下 SCK 为 1 CPOL=1
SPI2->CR1|=1<<0; //数据采样从第二个时间边沿开始,CPHA=1
//对 SPI2 属于 APB1 的外设.时钟频率最大为 36M.
SPI2->CR1|=3<<3; //Fsck=Fpclk1/256
SPI2->CR1|=0<<7; //MSBfirst
SPI2->CR1|=1<<6; //SPI 设备使能
SPI2_ReadWriteByte(0xff); //启动传输
}
//---------------------------------------------------
u8 SPI2_ReadWriteByte(u8 TxData)
{
u16 retry=0;
while((SPI2->SR&1<<1)==0) //等待发送区空
{
retry++;
if(retry>=0XFFFE)return 0; //超时退出
}
SPI2->DR=TxData; //发送一个 byte
retry=0;
while((SPI2->SR&1<<0)==0) //等待接收完一个 byte
{
retry++;
if(retry>=0XFFFE)return 0; //超时退出
}
return SPI2->DR; //返回收到的数据
}
spi2.h
#ifndef __SPI_H
#define __SPI_H
#include "sys.h"
// SPI 总线速度设置
#define SPI_SPEED_2 0
#define SPI_SPEED_4 1
#define SPI_SPEED_8 2
#define SPI_SPEED_16 3
#define SPI_SPEED_32 4
#define SPI_SPEED_64 5
#define SPI_SPEED_128 6
#define SPI_SPEED_256 7
void SPI2_Init(void); //初始化 SPI2 口
void SPI2_SetSpeed(u8 SpeedSet); //设置 SPI2 速度
u8 SPI2_ReadWriteByte(u8 TxData); //SPI2 总线读写一个字节
#endif
1. 查看 APIO 的資料,把 SPI1 的 "REMAP” 里面对应的 GPIO pin 脚选定。
选 pin 脚的事情要好好看看!
A。 没有 SPI2 的复用資料?
因为没有 SPI2 資料表比较,很容易就忽略了 **“NSS”**的使用技巧。从复用表上了解到需要用到的 pin 脚有 4 个,NSSSCKMISOMOSI. 再看看 nano 的程式
GPIOB->CRH|=0XBBB00000; //PB13/14/15 复用
GPIOB->ODR|=0X7<<13; //PB13/14/15 上拉
只定义了 3 个 脚位,就是 SCKMISOMOSI。nano 資料说明是 “使用的是 PB13、14、15 这 3 个(SCK.、MISO、MOSI,CS 使用软件管理方式),所以设置这三个为复用功能 IO”。
再查了下网络其他讨论 STM32F103 的文章,有许多负面的声音。不过,没关系,我们只要知道怎么用就好。
B。选用 nano 预留,没其他使用的脚位
SPI1 的 PA4567 这一组可以使用。
为了日后使用方便,我们把复用 GPIO 另外定义如下:
复用的 IO 要用 0xB. 没有定义 PA4.
void SPI1_GPIO_Init(void)
{
RCC->APB2ENR|=1<<3; //PORTA selected
AFIO->MAPR&=!(1)<<0; //SPI1_REMAP=0, pin out PA4,5,6,7
//SPI set GPIO output
GPIOA->CRL&=0X000FFFFF; //clear PA5,6,7
GPIOA->CRL|=0XBBB00000;//PA5,6,7 '1011'
GPIOA->ODR|=0X7<<5; //PA5,6,7 high
}
2. 进RCC,要把 SPI1 的开关打开
从資料上看到 SPI1 是在 RCC->APB2ENR 的 pin 12.
所以:
RCC->APB2ENR|=1<<12; //SPI1 enable, APB2ENR bit12
3.设定 SPI1 的相关参数。
参考STM32F103 的 資料,SPI 的主要设定都在 CR1,如下:
再参考其他程式 和 nano 板的程式,改写成下面这样:
// ====setting SPI
SPI1->CR1|=0<<10;// dual-channel
SPI1->CR1|=1<<8; //if SSM=1,internal slave
SPI1->CR1|=1<<2; //set as a SPI master
上一篇:STM32使用UCOSII支持低功耗模式
下一篇:STM32F103RB 实作笔记(八)- IWDG 内部看门狗试验
推荐阅读最新更新时间:2024-11-13 21:06
设计资源 培训 开发板 精华推荐
- 使用 Cypress Semiconductor 的 S6AL211 的参考设计
- DC1790A-B,基于 LTM2886-5S SPI 模块隔离器@5V 电源的演示板
- L7808A 远程关断稳压器的典型应用
- 人才qq
- 使用 Semtech 的 SC2610AMSTR 的参考设计
- 自制键盘x77
- LTC3615HFE-1 双路 3A 同步降压型 DC/DC 转换器用于 DDR 存储器终端的典型应用
- LT3756IUD-2 94% 效率 30W 白光 LED 前照灯驱动器的典型应用电路
- TS39103CP518 RO 1A、1.8V超低压差多功能稳压器典型应用电路
- 用于医疗的 2.5V ADC 单端至差分转换
- 第二季学习体验活动风暴来袭!
- “集齐五友”参与KW41Z创意征集活动,赢100元京东卡!
- 报名赢红包,到场抽开发板|2021 RT-Thread 开发者大会等你约!
- 有奖直播:低功耗、小尺寸&高温环境、带触摸功能——瑞萨电子最新16位RL78/G系列单片机介绍
- 有奖直播报名|瑞萨RA MCU家族成员快速增长,助力打造安全稳定的工业控制系统
- 有奖直播:【瑞萨电子推出针对血糖仪应用的内置模拟前端的RL78/L1A系列微控制器】
- 有奖活动|Mentor PCB 手册:《利用自动验证消除原理图设计错误》
- 半导体品牌知名度问卷调查
- 有奖评测:50套来自恩智浦全新快速物联网原型设计套件(价值350元)
- 深入东芝参考设计库:夯实您的设计库,让您的设计更出彩