STM32寄存器编码流程总结(上部)

目录

一、GPIO

1.时钟的配置

cpp 复制代码
//开启引脚的时钟
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;

2.设置GPIO的工作模式

cpp 复制代码
//PA0的工作模式为通用推挽输出模式
//CNF选择输入或输出的不同模式
GPIOA->CRL &= ~GPIO_CRL_CNF0;
//MODE选择引脚为输出或输入,以及输出的频率
GPIOA->CRL |= GPIO_CRL_MODE0; 

3.设置引脚的电平

当引脚为输出时进行设置

cpp 复制代码
//将PA0设置为输出低电平
GPIOA->ODR &= ~GPIO_ODR_ODR0;

二、中断系统

1.时钟的配置

cpp 复制代码
//开启引脚的时钟
RCC->APB2ENR |= RCC_APB2ENR_IOPFEN;
//开启AFIO引脚复用选择器的时钟
RCC->APB2ENR |= RCC_APB2ENR_AFIOEN;

2.设置GPIO的工作模式

cpp 复制代码
//将PF10设置为上下拉输入模式
GPIOF->CRH &= ~GPIO_CRH_MODE10;
GPIOF->CRH |= GPIO_CRH_CNF10_1;
GPIOF->CRH &= ~GPIO_CRH_CNF10_0;
//设置PF10的电平为低电平,确认其为下拉输入模式
GPIOF->ODR &= ~GPIO_ODR_ODR10;

3. 配置AFIO引脚复用

cpp 复制代码
//设置AFIO的第10个引脚为PF10复用
AFIO->EXTICR[2] |= AFIO_EXTICR3_EXTI10_PF;

4.EXTI的配置

cpp 复制代码
//设置为上升沿触发中断
EXTI->RTSR |= EXTI_RTST_TR10;
//开启10号引脚的中断请求
EXTI->IMR |= EXTI_IMR_MR10;

5.NVIC的配置

cpp 复制代码
//通过调用函数,简化配置
//设置优先级组
NVIC_SetPriorityGrouping(3);
//设置10传输中断请求的优先级
NVIC_SetPriority(EXTI15_10_IRQn,3);
//开启中断请求
NVIC_EnableIRQ(EXTI15_10_IRQn);

6.中断处理程序

cpp 复制代码
//函数名已经定义过,直接重写
void EXTI15_10_IRQHandler(void)
{
	//首先清除中断标志位
	EXTI->PR |= EXTI_PR_PR10;
	/* 执行中断的代码 */
}

三、USART串口通信

1.时钟的配置

cpp 复制代码
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
//开启串口的时钟
RCC->APB2ENR |= RCC_APB2ENR_USART1EN;

2.设置GPIO的工作模式

cpp 复制代码
//配置输出引线,为复用推挽输出;
GPIOA->CRH |= GPIO_CRH_MODE9;
GPIOA->CRH |= GPIO_CRH_CNF9_1;
GPIOA->CRH &= ~GPIO_CRH_CNF9_0;
//配置输入引线,为浮空输入
GPIOA->CRH &= ~GPIO_CRH_MODE10;
GPIOA->CRH |= GPIO_CRH_CNF10_0;
GPIOA->CRH &= ~GPIO_CRH_CNF10_1;

3.串口配置

cpp 复制代码
//直接给BRR寄存器赋值
USRAT1->BRR = 0x271;

//开启各种使能
//开启USART1的使能
USART1->CR1 |= USART_CR1_UE;
//开启发送和接收使能
USART1->CR1 |= USART_CR1_TE;
USART1->CR1 |= USART_CT1_RE;

//设置数据帧的格式
//数据帧的有效数据为8位
USART1->CR1 &= ~USART_CR1_M;
//关闭校验位,开启则有效位置1,变为9位
USART1->CR1 &= ~USART_CR1_PCE;
//配置停止位
USART1->CR2 &= ~USART_CR2_STOP;

//开启中断使能
//空闲线路中断开启
USART1->CR1 |= USART_CR1_IDLEIE;
//接收非空中断开启
USART1->CR1 |= USART_CR1_RXNEIE;

4.NVIC的配置

cpp 复制代码
NVIC_SetPriorityGrouping(3);
NVIC_SetPriority(USART1_IRQn,3);
NVIC_EnableIRQ(USART1_IRQn);

5.收发数据

cpp 复制代码
//发送数据
//采用轮询的方式进行发送数据
void USART_SendChar(uint8 data){
	//轮询判断SR中TXE是否为1,表示是否发送完毕
	while((USART1->SR & USART_SR_TXE) == 0)
	{}

	//发送完,则添加数据
	USART1->DR = data;
}

//接收数据
//采用中断方式
void USART1_IRQHandler(void){
	//接收非空时读取数据
	if(USART1->SR & USART_SR_RXNE){
		USART1->DR;
	}
	//线路空闲,接收完毕清除IDLE标志位
	else if(USART1->SR & USART_SR_IDLE)
	{
		USART1->DR;
	}
}

四、I2C通讯

1.时钟的配置

cpp 复制代码
RCC->APB2ENR |= RCC_APB2ENR_IOPBEN;
//开启I2C2的时钟
RCC->APB1ENR |= RCC_APB1ENR_I2C2EN;

2.设置GPIO的工作模式

cpp 复制代码
//将引脚设置为复用开漏输出
GPIOB->CRH |= (GPIO_CRH_MODE10 | GPIO_CRH_MODE11 |GPIO_CRH_CNF10 | 
				GPIO_CRH_MCNF11);

3.I2C2的配置

cpp 复制代码
//选择硬件模式为I2C模式
I2C2->CR1 &= ~I2C_CR1_SMBUS;
//选择传输速度,为标志模式
I2C2->CCR &= ~I2C_CCR_FS;
//配置其输入的时钟频率
I2C2->CR2 |= 36;
//配置CCR,高电平的占比时间,对应数据传输速率100kb/s,高电平时间为5us
I2C2->CCR |= 180; //为36 * 5
//配置TRISE,SCL上升沿最大时钟周期数 + 1
I2C2->TRISE |= 37;
//开启I2C2使能
I2C2->CR1 |= I2C_CR1_PE;

4.定义起始和结束信号函数

cpp 复制代码
//发出起始信号
uint8_t I2C_Start(void){
	//产生一个起始信号
	I2C2->CR1 |= I2C_CR1_START;
	//引入超时时间
	uint16_t timeout = 0xffff;
	//等待起始信号发送
	while((I2C2->SR1 & I2C_SR1_SB) == 0 && timeout){
		timeout--;
	}
	return timeout ? 1 : 0;
}

//发出停止信号
void I2C_Stop(void){
	I2C2->CR1 |= I2C_CR1_STOP;
}

5.定义主机应答和非应答信号函数

cpp 复制代码
//应答信号
void I2C_Ack(void){
	I2C2->CR1 |= I2C_CR1_ACK;
}
//非应答信号
void I2C_Nack(void){
	I2C2-CR1 &= ~I2C_CR1_ACK;
}

6.定义发送设备地址和数据函数

cpp 复制代码
//发送设备地址,并等待应答
uint8_t I2C_SendAddr(uint8_t addr){
	//将地址写入DR
	I2C2->DR = addr;
	//引入超时时间
	uint16_t timeout = 0xffff;
	//等待应答
	while((I2C2->SR1 & I2C_SR1_ADDR) == 0 && timeout){
		timeout--;
	}
	//访问SR2.清除ADDR标志位
	if(timeout > 0){
		I2C2->SR2;
	}
	return timeout ? 1 : 0;
}

//发送数据,并等待应答
uint8_t I2C_Sendbyte(uint8_t byte){
	//等待DR为空
	uint16_t timeout = 0xffff;
	while((I2C2->SR1 & I2C_SR1_TXE) == 0 && timeout){
		timeout--;
	}
	//将数据写入DR中
	I2C2->DR = byte;
	//等待应答
	timeout = 0xffff;
	while((I2C2->SR1 & I2C_SR1_BTF) == 0 && timeout){
		timeout--;
	}
	return timeout ? 1 : 0;
}

7.定义接收数据函数

cpp 复制代码
uint8_t I2C_ReadByte(void){
	//等待DR填满
	timeout = 0xffff;
	while((I2C2->SR1 & I2C_SR1_RXNE) == 0 && timeout){
		timeout--;
	}
	return timeout ? I2C3->DR : 0;
}

五、高级定时器

1.时钟的配置

cpp 复制代码
RCC->APB2 |= RCC_APB2ENR_IOPAEN;
//开启高级定时器的时钟
RCC->APB2 |= RCC_APB2ENR_TIM1EN;

2.设置GPIO的工作模式

cpp 复制代码
//位复用推挽输出
GPIOA->CRH |= GPIO_CRH_MODE8;
GPIOA->CRH |= GPIO_CRH_CNF8_1;
GPIOA->CRH &= ~GPIO_CRH_CNF8_0;

3.定时器配置

cpp 复制代码
//预分频值,其为10000 Hz
TIM1->PSC = 7199;
//重装载值。得到0.5s产生一次溢出
TIM1->ARR = 4999;
//设置计数方向
TIM1->CR1 &= ~TIM_CR1_DIR;
//重复计数
TIM1->RCR = 4;

//输出通道配置
//配置通道的输出模式
TIM1->CCMR1 &= ~TIM_CCMR1-CC1S;
//配置通道具体模式,为PWM1
TIM1->CCMR1 |= TIM_CCMR1_OC1M_2;
TIM1->CCMR1 |= TIM_CCMR1_OC1M_1;
TIM1->CCMR1 &= ~TIM_CCMR1_OC1M_0;
//配置占空比
TIM1->CCR1 = 2500;
//配置极性
TIM1->CCER &= ~TIM_CCER_CC1P;

//手动产生一个更新事件,刷新寄存器的值
TIM1->CR1 |= TIM_CR1_URS;
TIM1->EGR |= TIM_EGR_UG;

//开启使能
TIM1->CCER |= TIM_CCER_CC1E;
//主输出使能
TIM1->BDTR |= TIM_BDTR_MOE;

4.定时器开关

cpp 复制代码
//定时器开函数
void TIM1_Start(void){
	TIM1->CR1 |= TIM_CR1_CEN;
}

//定时器关函数
void TIM1_Stop(void){
	TIM1->CR1 &= ~TIM_CR1_CEN;
}

六、DMA存储访问

1.时钟的配置

cpp 复制代码
RCC->AHBENR |= RCC_AHBENR_DMA1EN;

2.DMA配置

cpp 复制代码
//配置数据传输方向,存储器到存储器,从外设读
DMA1_Channel1->CCR |= DMA_CCR1_MEM2MEM;
DMA11_Channel1->CCR &= ~DMA_CCR1_DIR;

//配置数据宽度,为8位
DMA1_Channel1->CCR &= ~DMA_CCR1_PSIZE;
DMA1_Channel1->CCR &= ~DMA_CCR1_MSIZE;

//开启地址自增
DMA1_Channel1->CCR |= DMA_CCR1_PINC;
DMA1_Channel1->CCR |= DMA_CCR1_MINC;

//开启数据传输完成中断标志
DMA1_Channel1->CCR |= DMA_CCR1_TCIE;

3.NVIC配置

cpp 复制代码
NVIC_SetPriorityGrouping(3);
NVIC_SetPriority(DMA1_Channel1_IRQn,2);
NVIC_EnableIRQ(DMA1_Channel1_IRQn);

4.定义数据传输

cpp 复制代码
void DMA1_Transmit(uint32_t srcAddr,uint32_t destAddr,uint16_t dataLen)
{
	//设置外设地址
	DMA1_Channel1->CPAR = srcAddr;
	//设置存储器地址
	DMA1_Channel1->CMAR = destAddr;
	//设置传输的数据量
	DMA1_Channel1->CNDTR = dataLen;
	//开启通道,开始传输数据
	DMA1_Channel1->CCR |= DMA_CCR1_EN;
}

七、ADC数模转换

1.时钟的配置

cpp 复制代码
//开启ADC
RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;
//开启ADC的分频
RCC->CFGR |= RCC_CFGR_ADCPRE_1;
RCC->CFGR &= ~RCC_CFGR_ADCPRE_0;

2.设置GPIO的工作模式

cpp 复制代码
//将PC0设置为模拟输入,00 00
GPIOC->CRL &= ~(GPIO_CRL_MODE0 | GPIO_CRL_CNF0); 

3.ADC配置

cpp 复制代码
//使用单通道模式
//配置工作模式:禁用扫描模式
ADC1->CR1 &= ~ADC_CR1_SCAN;
//启用连续转换模式
ADC1->CR2 |= ADC_CR2_CONT;
//数据右对齐(默认)
ADC1->CR2 &= ~ADC_CR2_ALIGN;
//设置通道采样时间,001
ADC1->SMPR1 &= ~ADC_SMPR1_SMP10;
ADC1->SMPR1 |= ADC_SMPR1_SMP10_0;
//规则组通道序列配置
//规则组中的通道个数 L
ADC1->SQR1 &= ~ADC_SQR1_L;
//将通道号10保存到序列中的第一位
//进行清零
ADC1->SQR3 &= ~SQR3_SQ1;
ADC1->SQR3 |= 10 << 0;
//选择软件触发AD转换
//先开启外部触发
ADC1->CR2 |= ADC_CR2_EXTTRIG;
//选择软件触发
ADC1->CR2 |= ADC_CR2_EXTSEL;

4.开启转换

cpp 复制代码
//上电唤醒
ADC1->CR2 |= ADC_CR2_ADON;
//执行校准
ADC1->CR2 |= ADC_CR2_CAL;
//判断校准完成
while(ADC1->CR2 & ADC_CR2_CAL){}
//启动转换
ADC1->CR2 |= ADC_CR2_SWSTART;
//等待转换完成
while((ADC1->SR & ADC_SR_EOC) == 0){}

5.返回模拟电压值

cpp 复制代码
//计算电压值
return ADC1->DR * 3.3 / 4095;

八、API通信

1.时钟的配置

cpp 复制代码
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
RCC->APB2ENR |= RCC_APB2ENR_IOPCEN;
RCC->APB2ENR |= RCC_APB2ENR_SPI1EN;

2.设置GPIO的工作模式

cpp 复制代码
//推挽输出 00 11
GPIOC->CRH |= GPIO_CRH_MODE13;
GPIOC->CRH &= ~GPIO_CRH_CNF13;
//复用推挽输出 10 11
GPIOA->CRL |= GPIO_CRL_MODE5;
GPIOA->CRL |= GPIO_CRL_CNF5_1;
GPIOA->CRL &= ~GPIO_CRH_CNF5_0;

GPIOA->CRL |= GPIO_CRL_MODE7;
GPIOA->CRL |= GPIO_CRL_CNF7_1;
GPIOA->CRL &= ~GPIO_CRH_CNF7_0;
//该引脚为MISO,改为浮空输入
GPIOA->CRL &= ~GPIO_CRL_MODE6;
GPIOA->CRL |= GPIO_CRL_CNF6_0;
GPIOA->CRL &= ~GPIO_CRH_CNF6_1;

3.SPI相关配置

cpp 复制代码
//配置SPI为主模式
SPI1->CR1 |= SPI_CR1_MSTR;
//使用软件控制片选信号,直接拉高,用硬件则为接入3.3V
SPI1->CR1 |= SPI_CR1_SSM;
SPI1->CR1 |= SPI_CR1_SSI;
//配置工作模式0,时钟极性和相位
SPI1->CR1 &= ~SPI_CR1_CPOL;
SPI1->CR1 &= ~SPI_CR1_CPHA;
//配置时钟分频系数,选择001
SPI1->CR1 &= ~SPI_CR1_BR;
SPI1->CR1 |= SPI_CR_BR_0;
//设置数据帧格式
SPI1->CR1 &= ~SPI_CR1_DFF;
//配置高位先行MSB
SPI1->CR1 &= ~SPI_CR1_LSBFIRST;
//SPI模块使能
SPI1->CR1 |= SPI_CR1_SPE;

4.交换一个字节的数据

cpp 复制代码
//将需要发送的数据写入发送缓冲区
//等待发送缓冲区为空
while((SPI->SR &SPI_SR_TXE) == 0){}
//将数据写入DR中
SPI1->DR = byte;

//读取MISO发来的数据
//等待接收缓冲区为非空
while((SPI1->SR & SPI_SR_RXNE) == 0){}

return SPI1->DR;

九、FSMC控制器

1.时钟的配置

cpp 复制代码
RCC->AHBENR |= RCC_AHBENR_FSMCEN;
RCC->APB2ENR |= (
RCC_APB2ENR_IOPDEN |
RCC_APB2ENR_IOPEEN |
RCC_APB2ENR_IOPFEN |
RCC_APB2ENR_IOPGEN)

2.设置GPIO的工作模式

cpp 复制代码
//写一部分
//配置地址线
//引脚模式为复用推挽输出 CNF-10,MODE-11
GPIOF->CRL |= (GPIO_CRL_MODE0 |
GPIO_CRL_MODE1)

GPIOF->CRL &= ~(GPIO_CRL_CNF0_1 |
GPIO_CRL_CNF1_1)
GPIOF->CRL &= ~(GPIO_CRL_CNF0_0 |
GPIO_CRL_CNF1_0)

//配置数据线
//复用推挽输出 CNF-10,MODE-11
GPIOD->CRH |= (GPIO_CRL_MODE14 |
GPIO_CRL_MODE15)

GPIOD->CRH &= ~(GPIO_CRL_CNF14_1 |
GPIO_CRL_CNF14_1)
GPIOD->CRH &= ~(GPIO_CRL_CNF15_0 |
GPIO_CRL_CNF15_0)

//配置控制信号引脚
//配置成复用推挽输出
GPIOD->CRL |= (GPIO_CRL_MODE4 | GPIO_CRL_MODE5);
GPIOD->CRL |= (GPIO_CRL_CNF4_1 | GPIO_CRL_CNF5_1);
GPIOD->CRL &= ~(GPIO_CRL_CNF4_0 | GPIO_CRL_CNF5_0);

3.配置FSMC

cpp 复制代码
//配置FSMC BCR3
//存储块使能
FSMC_Bank1->BTCR[4] |= FSMC_BCR3_MBKEN;
//时钟存储器类型00
FSMC_Bank1->BTCR[4] &= ~FSMC_BCR3_MTYP;
//禁止访问闪存
FSMC_Bank1->BTCR[4] &= ~FSMC_BCR3_FACCEN;
//数据宽度 -01
FSMC_Bank1->BTCR[4] &= ~FSMC_BCR3_MWID_1;
FSMC_Bank1->BTCR[4] |= FSMC_BCR3_MWID_0;
//地址数据线不复用,默认复用
FSMC_Bank1->BTCR[4] &= ~FSMC_BCR3_MUXEN;
//开启写使能
FSMC_Bank1->BTCR[4] |= FSMC_BCR3_WREN;

//配置FSMC BTR3
//地址建立时间
FSMC_Bank1->BTCR[5] &= ~FSMC_BTR3_ADDSET;
//数据保存时间
FSMC_Bank1->BTCR[5] &= ~FSMC_BTR3_DATAST;
FSMC_Bank1->BTCR[5] |= (71 << 8);

十、LCD显示

须结合FSMC进行
1.启动函数

cpp 复制代码
void LCD_Iint(void)
{
	FSMC_Init();
	LCD_Reset();
	LCD_BGOn();
	//寄存器配置函数直接抄写
	LCD_RegConfig();
}

2.复位函数

cpp 复制代码
GPIOG->ODR &= ~GPIO_ODR_ODR15; 
Delay_ms(100);
GPIOG->ODR |= GPIO_ODR_ODR15; 
Delay_ms(100);

3.开关背光

cpp 复制代码
//开启背光
GPIOB->ODR |= GPIO_ODR_ODR0;
//关闭背光
GPIOB->ODR &= ~GPIO_ODR_ODR0;

4.写命令和写数据函数

cpp 复制代码
//写命令
* LCD_ADDR_CMD = cmd;
//写数据
* LCD_ADDR_DATA = data;
相关推荐
大力水手偷吃菠菜变成米老鼠1 小时前
stm32 2.0.1
stm32
深圳市青牛科技实业有限公司4 小时前
GC6139——精准驱动,静享科技之美[特殊字符]
科技·单片机·嵌入式硬件·摄像头·医疗器械·机顶盒
J鸟6 小时前
嵌入式笔记 | 正点原子STM32F103ZET6 4 | 中断补充
笔记·stm32·单片机·嵌入式硬件
大力水手偷吃菠菜变成米老鼠7 小时前
stm32 2.0.2
stm32
羊羊一洋7 小时前
嵌入式stm32专业英语
stm32·单片机·嵌入式硬件
梁山1号9 小时前
【嵌入式硬件】 天线与距离问题
stm32·单片机·嵌入式硬件
chengg07699 小时前
数字与单片机仿真Proteus学习-03画第一个单片机电路图完成点灯
单片机·学习·proteus
黑果果的思考12 小时前
Touchgfx 自定义容器之间的交互操作
嵌入式硬件·交互
Yoie12 小时前
STM32使用HAL库,模拟UART输出字符串
stm32·单片机·嵌入式硬件