文章目录
一、GPIO的控制
要求:软件仿真,根据高8位pin输入电平,低8位输出相应的电平。写出main.c代码。
编程思路:
1、配置模式,P0.0~P0.7推挽输出,P0.8-P0.15浮空输入。
2、输入状态反映到对应引脚输出。
方式1:直接读、写输入\输出寄存器。
代码:
#include "stm32f10x.h"
int main(void)
{
//1、配置模式,P0.0~P0.7输出,P0.8-P0.15输入。
GPIOA->CRL = 0x33333333;//0x00000033前面的零是可以省略的
GPIOA->CRH = 0x44444444;
//2、输入状态反映到对应引脚输出。
while(1)
{
if((GPIOA->IDR&0x0100) == 0x0100) GPIOA->ODR |= 0x0001;
else GPIOA->ODR &= ~(0x0001);
if((GPIOA->IDR&0x0200) == 0x0200) GPIOA->ODR |= 0x0002;
else GPIOA->ODR &= ~(0x0002);
if((GPIOA->IDR&0x0400) == 0x0400) GPIOA->ODR |= 0x0004;
else GPIOA->ODR &= ~(0x0004);
if((GPIOA->IDR&0x0800) == 0x0800) GPIOA->ODR |= 0x0008;
else GPIOA->ODR &= ~(0x0008);
if((GPIOA->IDR&0x1000) == 0x1000) GPIOA->ODR |= 0x0010;
else GPIOA->ODR &= ~(0x0010);
if((GPIOA->IDR&0x2000) == 0x2000) GPIOA->ODR |= 0x0020;
else GPIOA->ODR &= ~(0x0020);
if((GPIOA->IDR&0x4000) == 0x4000) GPIOA->ODR |= 0x0040;
else GPIOA->ODR &= ~(0x0040);
if((GPIOA->IDR&0x8000) == 0x8000) GPIOA->ODR |= 0x0080;
else GPIOA->ODR &= ~(0x0080);
}
return 0;
}
方式2:通过位设置\清除寄存器 和 位清除寄存器控制。
位设置\清除寄存器BSRR,位清除寄存器BRR
BSRR位设置\清除寄存器
高16位清除为0,低16位设置为1.
BRR位清除寄存器
代码:
#include "stm32f10x.h"
int main(void)
{
GPIOA->CRL = 0x33333333;//0x00000033前面的零是可以省略的
GPIOA->CRH = 0x44444444;
while(1)
{
if((GPIOA->IDR&0x0100) == 0x0100) GPIOA->BSRR |= 0x0001;
else GPIOA->BRR |= 0x0001;
if((GPIOA->IDR&0x0200) == 0x0200) GPIOA->BSRR |= 0x0002;
else GPIOA->BRR |= 0x0002;
if((GPIOA->IDR&0x0400) == 0x0400) GPIOA->BSRR |= 0x0004;
else GPIOA->BRR |= 0x0004;
if((GPIOA->IDR&0x0800) == 0x0800) GPIOA->BSRR |= 0x0008;
else GPIOA->BRR |= 0x0008;
}
return 0;
}
方式3 位绑定
位绑定的定义:
位段
CortexTM-M3存储器映像包括两个位段(bit-band)区。这两个位段区将别名存储器区中的每个字映射到位段存储器区的一个位,在别名存储区写入-一个字具有对位段区的目标位执行读-改-写操作的相同效果。
在STM32F10xxx里,外设寄存器和SRAM都被映射到-一个 位段区里,这允许执行单一的位段的写和读操作。
下面的映射公式给出了别名区中的每个字是如何对应位带区的相应位的:
bit_ word_addr= bit_ band_base + (byte_offset * 32) + (bit_number * 4)
其中:
bit_ word addr 是别名存储器区中字的地址,它映射到某个目标位。
bit band_ base 是别名区的起始地址。
byte offset是包含 目标位的字节在位段里的偏移地址。
bit_ number是目标位所在位置(0-31)
个人理解
绑定地址 = 位绑定基地址+目标位偏移量
(不过这里的位绑定基地址是芯片制造商定好的地址。)
bit_ band_base 位绑定基地址
SRAM 的位绑定基地址:0x2200 0000
片上外设的位绑定的基地址:0x4200 0000
byte_ offset目标位偏移量
GPIOA->ODR为例子:
GPIOA->ODR地址
= GPIOA_BASE + 0x0C
= APB2PERIPH_BASE + 0x0800 + 0x0C
= PERIPH_BASE+0x10000+0x0800+0x0C
而 GPIOA->ODR 的目标位偏移量: byte_ offset = PERIPH_BASE+0x10000+0x0800+0x0C - PERIPH_BASE = 0x00010800C
以计算GPIOA->ODR 的 第n位绑定地址为例子:
bit_word_addr = 片上外设别名地址 + GPIOA->ODR相对GPIOA的偏移地址 + n * 4
bit_word_addr = 0x42000000 + 0x00010800C + n * 4
相关寄存器:
学习截图:
代码:
注意IDR绑定的位是第8位,不是第0位!!!
#include "stm32f10x.h"
int main(void)
{
//配置GPIO
GPIOA->CRL = 0x33333333;
GPIOA->CRH = 0x44444444;
//GPIOA->ODR地址 = (int*)(GPIOA_BASE+0x0C+0*4)
//= (int*)((APB2PERIPH_BASE + 0x0800)+0x0C+0*4)
//= (int*)(((PERIPH_BASE + 0x10000) + 0x0800)+0x0C+0*4)
//= (int*)(((0x40000000 + 0x10000) + 0x0800)+0x0C+0*4)
//= (int*)(0x4001080C)
int *PAO0 = (int*)(0x42000000 + (0x4001080C - 0x40000000)*32 +0*4);
//GPIOA->IDR地址 = GPIOA_BASE + 0x08
//= (int*)((APB2PERIPH_BASE + 0x0800)+0x08+0*4)
//= (int*)(((PERIPH_BASE + 0x10000) + 0x0800)+0x08+0*4)
//= (int*)(((0x40000000 + 0x10000) + 0x0800)+0x08+0*4)
//= (int*)(0x40010808)
int *PAI0 = (int*)(0x42000000 + (0x40010808 - 0x40000000)*32 +8*4);
while(1)
{
//位绑定
if(*PAI0 == 1) *PAO0 = 1;
else *PAO0 = 0;
//下面与上面的位绑定作对比
if((GPIOA->IDR&0x0200) == 0x0200) GPIOA->BSRR |= 0x0002;
else GPIOA->BRR |= 0x0002;
}
return 0;
}
公式代码:
(利用位的与运算保留 高位 或 低位)
(注意输入是高位,是8-15)
#include "stm32f10x.h"
#define GPIOA_ODR (GPIOA_BASE+0x0C)
#define GPIOA_IDR (GPIOA_BASE+0x08)
#define BitBand(Addr,bitNum) *((volatile unsigned long *)((Addr&0xf0000000)+0x2000000+((Addr&0xfffff)<<5)+(bitNum<<2)))
#define PAout(n) BitBand(GPIOA_ODR,n)
#define PAin(n) BitBand(GPIOA_IDR,n)
int main(void)
{
GPIOA->CRL = 0x33333333;//0x00000033前面的零是可以省略的
GPIOA->CRH = 0x44444444;
while(1)
{
//位绑定
if(PAin(8) == 1)
PAout(0) = 1;
else
PAout(0) = 0;
if(PAin(9) == 1)
PAout(1) = 1;
else
PAout(1) = 0;
if(PAin(10) == 1)
PAout(2) = 1;
else
PAout(2) = 0;
}
return 0;
}
二、通信。
通信就是指微处理机与外设交换数据的过程。
通信基本方式:
方式一:并行通信(多车道,多窗口)。
数据的各数位同时传输。
方式二:串行通信(单车道,单窗口)。
数据按位一位位的传输。
串行通信种类:
种类一:单工。
只允许一方发给另一方。
种类二:半双工。(对讲机)
双方可以相互通信,但是不能同时发送、同时接收。
种类三:全双工。
双方可以同时相互通信。
串行通信的标准:
标准1:UART 异步通信
异步通信协议:
异步通信协议需要定义5个方面的内容:
1、起始位。
2、数据位。
3、奇偶校验位。
4、停止位。
5、波特率(通信速度,因为通信双方没有时钟)。
异步通信应用场合:
1.芯片间的近距离通信。
2.与PC机的通信。
3.模块之间的远距离通信。
用较高的电压差表示逻辑“0”、“1”
stm32f10x USART框图
stm32f10x波特率的计算
设波特率位9600,根据公式
9600 = 7210001000/(16*U)
分频值U = 72 * 1000 * 1000/(9600 * 16) = 468.75
DIV_Mantissa = 468 = 0x1d4;
DIV_Fraction = 16 * 0.75 = 12 = 0x0C
仿真代码
晶振调为8Mhz
main.c 寄存器代码
#include "stm32f10x.h"
typedef unsigned char u8;
typedef unsigned short int u16;
typedef unsigned int u32;
//系统时钟初始化函数
//pll:选择的倍频数,从2开始,最大值为16
void Stm32_Clock_Init(void)
{
/*----------使用外部RC晶振----------*/
RCC_DeInit() ;
//初始化为缺省值
RCC_HSEConfig(RCC_HSE_ON); //使 能外部的高速时钟
while (RCC_GetFlagStatus(RCC_FLAG_HSERDY) == RESET); //等 待外部高速时钟使能就绪
RCC_HCLKConfig (RCC_SYSCLK_Div1) ;
//HCLK = SYSCLK
RCC_PCLK2Config(RCC_HCLK_Div1) ;
//PCLK2 =HCLK
RCC_PCLK1Config(RCC_HCLK_Div2) ;
//PCLK1 = HCLR/2
RCC_PLLConfig (RCC_PLLSource_HSE_Div1, RCC_PLLMul_9); //PLLCLK = 8MHZ * 9 =72MHZ
RCC_PLLCmd(ENABLE) ;
//Enable PLLCLK
while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET); //Wait till PLLCLK is ready
RCC_SYSCLKConfig (RCC_SYSCLKSource_PLLCLK) ;
//Select PLL as system clock
while (RCC_GetSYSCLKSource () !=0x08) ;
//wait till PLL is used as system clock source
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1,ENABLE);//使能外设
}
int main(void)
{
u16 M,F,BRR;
float Div;
u32 Bound;
u8 data = 'A';
u8 i ;
Stm32_Clock_Init();
GPIOA->CRH&=0XFFFFF00F;//IO状态设置
GPIOA->CRH|=0X000008B0;//IO状态设置,1000复用推挽输出
//USART设置:UE位使能USART1,M位来定义字长,停止位,波特率,TE发送使能位、
//UE:USART1->CR1 的13位
USART1->CR1 |= (1<<13);//UE使能
USART1->CR1 &= ~(1<<12);//M字长,8bit
//或者USART1->CR2 &= ~(3<<12);或者USART1->CR2 &= ~((1<<13)|(1<<12));
USART1->CR2 &= ~(3<<12);//配置停止位,1bit
USART1->CR1 |= (1<<3);//TE位发送,使能发送
//波特率设置
Bound = 9600;
Div = (float)(72*1000*1000)/(Bound*16);//整数运算要强制转化成浮点数才能编变成浮点数。
M = Div;
F = (Div - M)*16;
BRR = (M<<4|F);//不是 0x10+0x01 = 0x11,而是0x10|0x01 = 0x11;
USART1->BRR = BRR;
//发送字符'A'及其后面的20个字符到USART的TXD
for(i=0;i<20;i++)
{
USART1->DR = data;
data++;
while((USART1->SR & (1<<6)) == 0);//依据SR-TC标志位,判断是否发送完毕。1表示发送完毕,0表示未发送完毕。
}
return 0;
}
main.c 库函数代码
#include "stm32f10x.h"
typedef unsigned char u8;
typedef unsigned short int u16;
typedef unsigned int u32;
//系统时钟初始化函数
//pll:选择的倍频数,从2开始,最大值为16
void Stm32_Clock_Init(void)
{
/*----------使用外部RC晶振----------*/
RCC_DeInit() ;
//初始化为缺省值
RCC_HSEConfig(RCC_HSE_ON); //使 能外部的高速时钟
while (RCC_GetFlagStatus(RCC_FLAG_HSERDY) == RESET); //等 待外部高速时钟使能就绪
RCC_HCLKConfig (RCC_SYSCLK_Div1) ;
//HCLK = SYSCLK
RCC_PCLK2Config(RCC_HCLK_Div1) ;
//PCLK2 =HCLK
RCC_PCLK1Config(RCC_HCLK_Div2) ;
//PCLK1 = HCLR/2
RCC_PLLConfig (RCC_PLLSource_HSE_Div1, RCC_PLLMul_9); //PLLCLK = 8MHZ * 9 =72MHZ
RCC_PLLCmd(ENABLE) ;
//Enable PLLCLK
while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET); //Wait till PLLCLK is ready
RCC_SYSCLKConfig (RCC_SYSCLKSource_PLLCLK) ;
//Select PLL as system clock
while (RCC_GetSYSCLKSource () !=0x08) ;
//wait till PLL is used as system clock source
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1,ENABLE);
}
void GPIO_Config()
{
GPIOA->CRH&=0XFFFFF00F;//IO状态设置
GPIOA->CRH|=0X000008B0;//IO状态设置,1000复用推挽输出
}
void USART_Config(u32 BaudRate)
{
USART_InitTypeDef USARTST;
USARTST.USART_WordLength = USART_WordLength_9b;
USARTST.USART_StopBits = USART_StopBits_1;
USARTST.USART_Parity = USART_Parity_No;
USARTST.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USARTST.USART_Mode = USART_Mode_Tx|USART_Mode_Rx;
USARTST.USART_BaudRate = BaudRate;
USART_Init(USART1,&USARTST);//配置USART1
USART_Cmd(USART1,ENABLE);//使能USART1
}
int main(void)
{
u8 data = 'A';
u8 i ;
Stm32_Clock_Init();
GPIO_Config();
USART_Config(9600);
for(i=0;i<20;i++)
{
USART_SendData(USART1,data);
data++;
while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);//判断标志位。
}
return 0;
}
USART库函数:
USART_init配置串口:
USART_Cmd使能串口:
USART_GetFlagStatus判断标志位:
RESET 和 SET 的值:
三、stm32库函数
stm32库函数是由st公司提供的API,开发者可以使用库函数来配置寄存器,使开发者摆脱最底层的寄存器操作。有着开发快速,易于阅读的优点。
它向下操作寄存器,向上提供操作配置寄存器的接口。
SMSIS(Contex MicroController Software Interface Standard)标准,ARM公司与其他外设厂家建立的标准。
来源:CSDN
作者:某风吾起
链接:https://blog.csdn.net/weixin_43871650/article/details/104131726