led长端接阳极,按钮看底部连线
#include "stm32f10x.h"
#include"delay.h"
int main(void)
{
//定时器
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);//STM32 的外设(如 GPIO)默认处于时钟关闭状态,
//使用前必须先使能对应时钟。GPIOC 挂载在 APB2 总线上,因此使用RCC_APB2PeriphClockCmd()函数。
GPIO_InitTypeDef GPIO_InitStruct={0};//一个内置结构体
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_13;//引脚
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_OD;//输出模式
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_2MHz;//输出速度
GPIO_Init(GPIOC,&GPIO_InitStruct);//将配置参数应用到 GPIOC 端口。
while(1)
{
GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_RESET);//1.模块,2.引脚,3.点亮(通用输出开漏
Delay(100);
GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_SET);
Delay(100);
}
}
设置系统板上绿灯闪烁
| GPIO_Mode_Out_PP | 通用输出推挽,push pull |
| GPIO_Mode_Out_OD | 通用输出开漏,open drain |
| GPIO_Mode_AF_pp | 复用输出推挽,AF=Alternate Function |
| GPIO_Mode_AF_OD | 复用输出开漏 |
| GPIO_Mode_IPU | 输入上拉,Input pull up |
| GPIO_Mode_IPD | 输入下拉Input pull down |
| GPIO_Mode_IN_FLOATING | 输入浮空 |
| GPIO_Mode_AIN | 模拟模式 Analog Input |
按钮点灯
#include "stm32f10x.h"
#include"delay.h"
int main(void)
{
//定时器
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitTypeDef GPIO_InitStruct={0};
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0;
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_2MHz;
GPIO_Init(GPIOA,&GPIO_InitStruct);//连接灯的部分
//GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_SET);
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_1;
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IPU;
GPIO_Init(GPIOA,&GPIO_InitStruct);//按钮的部分
while(1)
{//输入上拉,即按钮按下后输入比特为0:RESET
if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_1)==Bit_RESET){
GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_SET);//给灯写入1:Bit_SET
}else{
GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_RESET);
}
}
}
串口初始化
#include "stm32f10x.h"
#include"delay.h"
int main(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//是使能 USART1 的时钟
//开启通信接口
USART_Cmd(USART1,ENABLE);
//创建了一个USART_InitTypeDef类型的结构体变量USART_Struct,并对其进行初始化
USART_InitTypeDef USART_Struct;
USART_Struct.USART_BaudRate=115200;
USART_Struct.USART_Mode=USART_Mode_Rx | USART_Mode_Tx;
USART_Struct.USART_WordLength=USART_WordLength_8b;
USART_Struct.USART_StopBits=USART_StopBits_1;
USART_Struct.USART_Parity=USART_Parity_No;
//该函数会按照USART_Struct结构体中的参数配置,对 USART1 进行初始化。
USART_Init(USART1,&USART_Struct);
while(1)
{
}
}
为串口初始化IO引脚(USART1
| tx | PA9 |
| rx | PA10 |
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitTypeDef GPIO_InitStruct;
//PA9,tx
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_9;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_10MHz;
GPIO_Init(GPIOA,&GPIO_InitStruct);
//PA10 rx
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IPU;
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_10;
GPIO_Init(GPIOA,&GPIO_InitStruct);
//重映射,重映射后引脚更换:PB6:tx PB7:rx
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
GPIO_PinRemapConfig(GPIO_Remap_USART1,ENABLE);
//后面与之前设置引脚方式相同,GPIOA换为GPIOB,
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
GPIO_InitTypeDef GPIOin;
GPIOin.GPIO_Pin=GPIO_Pin_6;//PB6 tx
GPIOin.GPIO_Mode=GPIO_Mode_AF_PP;
GPIOin.GPIO_Speed=GPIO_Speed_10MHz;
GPIO_Init(GPIOB,&GPIOin);
GPIOin.GPIO_Mode=GPIO_Mode_IPU;
GPIOin.GPIO_Pin=GPIO_Pin_7;//PB7 rx
GPIO_Init(GPIOB,&GPIOin);
自定义数据发送函数
void My_USART_SendBytes(USART_TypeDef *USARTx,uint8_t *pData,uint16_t Size){
for(uint32_t i=0;i<Size;i++){
//等待发送数据寄存器为 空
while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
//写入发数据寄存器中
USART_SendData(USARTx,pData[i]);
}
//等待发送全部完成
while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET);
}
//重载内置函数,可以使用printf在串口调试助手收到数据
int fputc(int ch,FILE *f)
{
//等待发送数据寄存器为 空
while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
//一个字节一个字节发送
USART_SendData(USART1,(uint8_t)ch);
return ch;
}
| USART引脚 | 配置 | GPIO配置 |
| USARTx_TX | 全双工模式 | 推挽复用输出 |
| 半双工同步模式 | 推挽复用输出 | |
| USARTx_Rx | 全双工模式 | 浮空输入或上拉输入(最好上拉输入 |
| 半双工同步模式 | 未用 |
I2C引脚
| 复用功能 | I2C1_REMAP=0 | I2C_REMAP=1 | |
| I2C1 | I2C1_SCL | PB6 | PB8 |
| I2C1_SDA | PB7 | PB9 | |
| I2C2 | I2C2_SCL | 无重映射 | PB10 |
| I2C2_SDA | PB11 |
I2Cx_SCL:I2C时钟,开漏复用输出
I2Cx_SDA:I2C数据,开漏复用输出
void My_I2C_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
GPIO_PinRemapConfig(GPIO_Remap_I2C1,ENABLE);//重映射
//对PB8|9初始化
GPIO_InitTypeDef in;
in.GPIO_Mode=GPIO_Mode_AF_OD;
in.GPIO_Pin=GPIO_Pin_8|GPIO_Pin_9;
in.GPIO_Speed=GPIO_Speed_2MHz;
GPIO_Init(GPIOB,&in);
//初始化I2C
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE);
RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1,ENABLE);//施加复位信号
RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1,DISABLE);//释放复位信号
I2C_InitTypeDef I2c_Struct;
I2c_Struct.I2C_ClockSpeed=400000;//设置速度
I2c_Struct.I2C_DutyCycle=I2C_DutyCycle_2;//设置2:1的占空比
I2c_Struct.I2C_Mode=I2C_Mode_I2C;//标准模式
I2C_Init(I2C1,&I2c_Struct);
I2C_Cmd(I2C1,ENABLE);//闭合总开关
}
I2C发送字节(未成功
int My_I2C_SendBytes(I2C_TypeDef *I2Cx,uint8_t addr,uint8_t *pData,uint16_t Size)
{
//1.等待总线空闲
while(I2C_GetFlagStatus(I2Cx,I2C_FLAG_BUSY)==SET);//BUSY:总线标志位,0:空闲;1:忙
//2.发送起始位
I2C_GenerateSTART(I2Cx,ENABLE);//发送起始位
while(I2C_GetFlagStatus(I2Cx,I2C_FLAG_SB)==RESET);//SB:起始位发送状态;0:未发送;1:发送完成
//3.寻址阶段
I2C_ClearFlag(I2Cx,I2C_FLAG_AF);//清除AF标志位,AF:应答失败,1:未收到ACK
I2C_SendData(I2Cx,addr & 0xfe);//发送地址+RW#
while(1){
if(I2C_GetFlagStatus(I2Cx,I2C_FLAG_ADDR)==SET)break;//ADDR:寻址成功;
if(I2C_GetFlagStatus(I2Cx,I2C_FLAG_AF)==SET){
I2C_GenerateSTOP(I2Cx,ENABLE);//发送停止位并返回-1,寻址失败
return -1;
}
}
//清除ADDR
I2C_ReadRegister(I2Cx,I2C_Register_SR1);
I2C_ReadRegister(I2Cx,I2C_Register_SR2);
//4.发送数据
for(uint16_t i=0;i<Size;i++){
while(1){
if(I2C_GetFlagStatus(I2Cx,I2C_FLAG_AF)==SET){
I2C_GenerateSTOP(I2Cx,ENABLE);
return -2;//数据被拒收
}
if(I2C_GetFlagStatus(I2Cx,I2C_FLAG_TXE)==SET)break;
}
I2C_SendData(I2Cx,pData[i]);
}
while(1)
{
if(I2C_GetFlagStatus(I2Cx,I2C_FLAG_AF)==SET){
I2C_GenerateSTOP(I2Cx,ENABLE);
return -2;
}
if(I2C_GetFlagStatus(I2Cx,I2C_FLAG_BTF)==SET){
break;
}
}
I2C_GenerateSTOP(I2Cx,ENABLE);
return 0;
}
按4.4,点亮显示屏,但未亮。
int main(void)
{
My_I2C_Init();
uint8_t c[]={0x00,0x8d,0x14,0xaf,0xa5};
My_I2C_SendBytes(I2C1,0x78,c,5);
while(1)
{
}
}
I2C接收数据
int My_I2CReceiveBytes(I2C_TypeDef*I2Cx,uint8_t Addr,uint8_t*pBuffer,uint16_t Size)
{
//1.发送起始位
I2C_GenerateSTART(I2Cx,ENABLE);
while(I2C_GetFlagStatus(I2Cx,I2C_FLAG_SB)==RESET);
//2.寻址阶段
I2C_ClearFlag(I2Cx,I2C_FLAG_AF);
I2C_SendData(I2Cx,Addr|0x01);
while(1){
if(I2C_GetFlagStatus(I2Cx,I2C_FLAG_AF)==SET){
I2C_GenerateSTOP(I2Cx,ENABLE);
return -1;//寻址失败
}
if(I2C_GetFlagStatus(I2Cx,I2C_FLAG_ADDR)==SET)
{break;}
}
//3.接收数据
if(Size==1){
//清除ADDR
I2C_ReadRegister(I2Cx,I2C_Register_SR1);
I2C_ReadRegister(I2Cx,I2C_Register_SR2);
//ACK=0,STOP=1
I2C_AcknowledgeConfig(I2Cx,DISABLE);
I2C_GenerateSTOP(I2Cx,ENABLE);
//RxNE->1
while(I2C_GetFlagStatus(I2Cx,I2C_FLAG_RXNE)==RESET);
//读取数据
pBuffer[0]=I2C_ReceiveData(I2Cx);
}else if(Size==2){
//清除ADDR标志位
I2C_ReadRegister(I2Cx,I2C_Register_SR1);
I2C_ReadRegister(I2Cx,I2C_Register_SR2);
//ACK=1
I2C_AcknowledgeConfig(I2Cx,ENABLE);
//等待接收完成
while(I2C_GetFlagStatus(I2Cx,I2C_FLAG_RXNE)==RESET);
//读取第一个字节
pBuffer[0]=I2C_ReceiveData(I2Cx);
//ACK=0,STOP=1
I2C_AcknowledgeConfig(I2Cx,DISABLE);
I2C_GenerateSTOP(I2Cx,ENABLE);
//等待接收完成
while(I2C_GetFlagStatus(I2Cx,I2C_FLAG_RXNE)==RESET);
pBuffer[1]=I2C_ReceiveData(I2Cx);
}else{//size>2
//清除ADDR标志位
I2C_ReadRegister(I2Cx,I2C_Register_SR1);
I2C_ReadRegister(I2Cx,I2C_Register_SR2);
//ACK=1
I2C_AcknowledgeConfig(I2Cx,ENABLE);
for(uint16_t i=0;i<Size-1;i++){
//等待接收完成
while(I2C_GetFlagStatus(I2Cx,I2C_FLAG_RXNE)==RESET);
//读取数据
pBuffer[i]=I2C_ReceiveData(I2Cx);
}
//ACK=0,STOP=1
I2C_AcknowledgeConfig(I2Cx,DISABLE);
I2C_GenerateSTOP(I2Cx,ENABLE);
//等待接收完成
while(I2C_GetFlagStatus(I2Cx,I2C_FLAG_RXNE)==RESET);
pBuffer[Size-1]=I2C_ReceiveData(I2Cx);
}
return 0;
}
使用代码:当显示屏亮起,板载led亮
int main(void)
{
My_I2C_Init();
My_boardLED_Init();
uint8_t c[]={0x00,0x8d,0x14,0xaf,0xa5};
My_I2C_SendBytes(I2C1,0x78,c,5);
uint8_t rcvd;
My_I2CReceiveBytes(I2C1,0x78,&rcvd,1);
if((rcvd&(0x01<<6))==0){
GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_RESET);
}else{
GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_SET);
}
while(1)
{
}
}
按钮点灯高级版
int main(void)
{
button();
My_boardLED_Init();
uint8_t pre=Bit_SET,cur=Bit_SET;
uint8_t isan=0;
while(1)
{
cur=GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_8);
if(pre!=cur){
isan=1;
Delay(10);//防抖
}
if(isan==1&&pre==cur){
isan=0;
if(GPIO_ReadOutputDataBit(GPIOC,GPIO_Pin_13)==Bit_RESET){
GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_SET);
}else{
GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_RESET);
}
Delay(10);
}
}
}
void My_boardLED_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
GPIO_InitTypeDef in;
in.GPIO_Mode=GPIO_Mode_Out_OD;
in.GPIO_Pin=GPIO_Pin_13;
in.GPIO_Speed=GPIO_Speed_2MHz;
GPIO_Init(GPIOC,&in);
GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_RESET);//默认点亮
}
void button(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
GPIO_InitTypeDef in;
in.GPIO_Mode=GPIO_Mode_IPU;
in.GPIO_Pin=GPIO_Pin_8;
in.GPIO_Speed=GPIO_Speed_2MHz;
GPIO_Init(GPIOB,&in);
}
| 复用功能 | SPI1_REMAP=0 | ...=1 |
| SPI1_NSS | PA4 | PA15 |
| SPI1_SCK | PA5 | PB3 |
| SPI1_MISO | PA6 | PB4 |
| SPI1_MOSI | PA7 | PB5 |
spi初始化1
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1,ENABLE);
SPI_InitTypeDef spi;
spi.SPI_Mode=SPI_Mode_Master; // 配置为主机模式
spi.SPI_Direction=SPI_Direction_2Lines_FullDuplex; // 双线全双工模式
spi.SPI_DataSize=SPI_DataSize_8b; // 数据宽度为8位
spi.SPI_CPOL=SPI_CPOL_High; // 时钟极性:空闲时为高电平
spi.SPI_CPHA=SPI_CPHA_2Edge; // 时钟相位:第二个边沿采样
spi.SPI_FirstBit=SPI_FirstBit_MSB; // 高位在前
spi.SPI_BaudRatePrescaler=SPI_BaudRatePrescaler_64; // 波特率分频:64分频
spi.SPI_NSS=SPI_NSS_Soft; // 软件控制片选
SPI_Init(SPI1,&spi);
SPI_NSSInternalSoftwareConfig(SPI1,SPI_NSSInternalSoft_Set); // 内部NSS信号设置为高
使用w25q64模块保存数据
#include "stm32f10x.h" // 确保包含正确的头文件
#include<stdio.h>
#include"button.h"
void SPI1_init(void);
void spi_masttrans(SPI_TypeDef* SPIx, const uint8_t *pDataTx, uint8_t *pDataRx, uint16_t Size);
void savew25bits(uint8_t byte);
uint8_t loadw25bits(void);
void My_boardLED_Init(void);
Button_TypeDef button;
void button_in(void);
void but_cb(uint8_t click);
int main(void)
{
SPI1_init();
My_boardLED_Init();
button_in();
uint8_t b=loadw25bits();
if(b==1){
GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_SET);
}else if(b==0){
GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_RESET);
}
while(1)
{
My_Button_Proc(&button);
}
}
void but_cb(uint8_t click)
{
if(click==1){
if(GPIO_ReadOutputDataBit(GPIOC,GPIO_Pin_13)==Bit_RESET){
GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_SET);
savew25bits(0x01);
}else{
GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_RESET);
savew25bits(0x00);
}
}
}
void button_in(void)
{
Button_InitTypeDef bu={0};
bu.GPIOx=GPIOA;
bu.GPIO_Pin=GPIO_Pin_0;
bu.button_clicked_cb=but_cb;
My_Button_Init(&button,&bu);
}
void My_boardLED_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
GPIO_InitTypeDef in;
in.GPIO_Mode=GPIO_Mode_Out_OD;
in.GPIO_Pin=GPIO_Pin_13;
in.GPIO_Speed=GPIO_Speed_2MHz;
GPIO_Init(GPIOC,&in);
}
void SPI1_init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
GPIO_PinRemapConfig(GPIO_Remap_SPI1, ENABLE);
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitTypeDef in;
in.GPIO_Mode = GPIO_Mode_AF_PP;
in.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_5;
in.GPIO_Speed = GPIO_Speed_50MHz; // SPI通常需要更高速度
GPIO_Init(GPIOB, &in); // PB3 SCK, PB5 MOSI
in.GPIO_Mode = GPIO_Mode_IPU;
in.GPIO_Pin = GPIO_Pin_4;
GPIO_Init(GPIOB, &in); // PB4 MISO
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
in.GPIO_Mode = GPIO_Mode_Out_PP;
in.GPIO_Pin = GPIO_Pin_15;
in.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &in); // PA15 片选
GPIO_WriteBit(GPIOA, GPIO_Pin_15, Bit_SET); // 默认拉高片选
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
SPI_InitTypeDef spi;
spi.SPI_Mode = SPI_Mode_Master;
spi.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
spi.SPI_DataSize = SPI_DataSize_8b;
spi.SPI_CPOL = SPI_CPOL_Low;
spi.SPI_CPHA = SPI_CPHA_1Edge;
spi.SPI_FirstBit = SPI_FirstBit_MSB;
spi.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16; // 适当提高速度
spi.SPI_NSS = SPI_NSS_Soft;
spi.SPI_CRCPolynomial = 7; // 必须初始化的参数
SPI_Init(SPI1, &spi);
SPI_Cmd(SPI1, ENABLE); // 初始化时就使能SPI
}
// 修正函数名拼写和传输逻辑
void spi_masttrans(SPI_TypeDef* SPIx, const uint8_t *pDataTx, uint8_t *pDataRx, uint16_t Size)
{
for(uint16_t i = 0; i < Size; i++)
{
// 等待发送缓冲区为空
while(SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_TXE) == RESET);
SPI_I2S_SendData(SPIx, pDataTx[i]);
// 等待接收缓冲区有数据
while(SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_RXNE) == RESET);
if(pDataRx != NULL) // 确保接收缓冲区有效
{
pDataRx[i] = SPI_I2S_ReceiveData(SPIx);
}
else
{
// 不需要接收时仍需读取数据清除标志
SPI_I2S_ReceiveData(SPIx);
}
}
// 等待传输完成
while(SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_BSY) == SET);
}
void savew25bits(uint8_t byte)
{
uint8_t buffer[10];
// 1. 写使能
buffer[0] = 0x06;
GPIO_WriteBit(GPIOA, GPIO_Pin_15, Bit_RESET); // 拉低片选
spi_masttrans(SPI1, buffer, NULL, 1);
GPIO_WriteBit(GPIOA, GPIO_Pin_15, Bit_SET); // 拉高片选
// 2. 扇区擦除
buffer[0] = 0x20; // 扇区擦除命令
buffer[1] = 0x00; // 地址高位
buffer[2] = 0x00; // 地址中位
buffer[3] = 0x00; // 地址低位
GPIO_WriteBit(GPIOA, GPIO_Pin_15, Bit_RESET);
spi_masttrans(SPI1, buffer, NULL, 4);
GPIO_WriteBit(GPIOA, GPIO_Pin_15, Bit_SET);
// 3. 等待擦除完成
while(1)
{
GPIO_WriteBit(GPIOA, GPIO_Pin_15, Bit_RESET);
buffer[0] = 0x05; // 读状态寄存器命令
spi_masttrans(SPI1, buffer, buffer, 1);
// 发送一个空字节以读取状态
spi_masttrans(SPI1, buffer, buffer, 1);
GPIO_WriteBit(GPIOA, GPIO_Pin_15, Bit_SET);
if((buffer[0] & 0x01) == 0) // 检查忙标志
break;
}
// 4. 再次写使能(擦除后需要重新使能)
buffer[0] = 0x06;
GPIO_WriteBit(GPIOA, GPIO_Pin_15, Bit_RESET);
spi_masttrans(SPI1, buffer, NULL, 1);
GPIO_WriteBit(GPIOA, GPIO_Pin_15, Bit_SET);
// 5. 页编程
buffer[0] = 0x02; // 页编程命令
buffer[1] = 0x00; // 地址高位
buffer[2] = 0x00; // 地址中位
buffer[3] = 0x00; // 地址低位
buffer[4] = byte; // 要写入的数据
GPIO_WriteBit(GPIOA, GPIO_Pin_15, Bit_RESET);
spi_masttrans(SPI1, buffer, NULL, 5);
GPIO_WriteBit(GPIOA, GPIO_Pin_15, Bit_SET);
// 6. 等待编程完成
while(1)
{
GPIO_WriteBit(GPIOA, GPIO_Pin_15, Bit_RESET);
buffer[0] = 0x05; // 读状态寄存器命令
spi_masttrans(SPI1, buffer, buffer, 1);
spi_masttrans(SPI1, buffer, buffer, 1);
GPIO_WriteBit(GPIOA, GPIO_Pin_15, Bit_SET);
if((buffer[0] & 0x01) == 0) // 检查忙标志
break;
}
}
uint8_t loadw25bits(void)
{
uint8_t buffer[10] = {0};
// 读取数据命令和地址
buffer[0] = 0x03; // 读数据命令
buffer[1] = 0x00; // 地址高位
buffer[2] = 0x00; // 地址中位
buffer[3] = 0x00; // 地址低位
GPIO_WriteBit(GPIOA, GPIO_Pin_15, Bit_RESET);
// 发送命令和地址
spi_masttrans(SPI1, buffer, NULL, 4);
// 读取数据(发送一个空字节来获取返回数据)
spi_masttrans(SPI1, buffer, buffer, 1);
GPIO_WriteBit(GPIOA, GPIO_Pin_15, Bit_SET);
// 注意:移除了这里的GPIO初始化,避免干扰SPI功能
// 如果需要LED指示,应在单独的初始化函数中设置
return buffer[0]; // 返回读取到的数据
}
以USART模块的TXE标志位作中断控制灯闪烁快慢
#include "stm32f10x.h" // 确保包含正确的头文件
#include"delay.h"
#include<stdio.h>
#include"usart.h"
uint16_t a=1000;
void My_boardLED_Init(void);
void usartinit(void);
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
My_boardLED_Init();
usartinit();
My_USART_SendString(USART1,"HELLO");
while(1)
{
GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_SET);
Delay(a);
GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_RESET);
Delay(a);
}
}
void USART1_IRQHandler(void)
{
if(USART_GetFlagStatus(USART1,USART_FLAG_RXNE)==SET){
uint8_t da=USART_ReceiveData(USART1);
if(da=='0'){a=1000;}
else if(da=='1'){a=200;}
else if(da=='2'){a=50;}
}
}
void usartinit(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1,ENABLE);
GPIO_InitTypeDef in;
in.GPIO_Mode=GPIO_Mode_AF_PP;
in.GPIO_Pin=GPIO_Pin_9;
in.GPIO_Speed=GPIO_Speed_2MHz;
GPIO_Init(GPIOA,&in);
in.GPIO_Mode=GPIO_Mode_IPU;
in.GPIO_Pin=GPIO_Pin_10;
GPIO_Init(GPIOA,&in);
USART_InitTypeDef us;
us.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
us.USART_BaudRate=115200;
us.USART_Mode=USART_Mode_Rx | USART_Mode_Tx;
us.USART_Parity=USART_Parity_No;
us.USART_StopBits=USART_StopBits_1;
us.USART_WordLength=USART_WordLength_8b;
USART_Init(USART1,&us);
USART_Cmd(USART1,ENABLE);//必合总开关
//配置中断
USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);
//配置NVIC
NVIC_InitTypeDef nvic;
nvic.NVIC_IRQChannel=USART1_IRQn;
nvic.NVIC_IRQChannelPreemptionPriority=0;
nvic.NVIC_IRQChannelSubPriority=0;
nvic.NVIC_IRQChannelCmd=ENABLE;
NVIC_Init(&nvic);
}
void My_boardLED_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
GPIO_InitTypeDef in;
in.GPIO_Mode=GPIO_Mode_Out_OD;
in.GPIO_Pin=GPIO_Pin_13;
in.GPIO_Speed=GPIO_Speed_2MHz;
GPIO_Init(GPIOC,&in);
}
tim模块实现延迟
void tim3_init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE); // 使能定时器3的时钟(外设必须使能时钟才能工作)
// 配置定时器时基参数
TIM_TimeBaseInitTypeDef tim; // 定义定时器初始化结构体
tim.TIM_Prescaler=71; // 预分频器:72MHz/(71+1)=1MHz(定时器计数频率)
tim.TIM_Period=999; // 自动重装载值:计数到999后触发更新事件(1MHz/1000=1kHz,即1ms触发一次)
tim.TIM_CounterMode=TIM_CounterMode_Up; // 计数模式:向上计数(从0到999循环)
tim.TIM_RepetitionCounter=0; // 重复计数器:不使用(高级定时器才需要)
TIM_TimeBaseInit(TIM3,&tim); // 应用配置到定时器3
TIM_Cmd(TIM3,ENABLE); // 使能定时器3(开始计数)
// 配置定时器更新中断
TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE); // 允许定时器3的更新事件产生中断
// 配置中断控制器(NVIC)
NVIC_InitTypeDef nv; // 定义NVIC初始化结构体
nv.NVIC_IRQChannel=TIM3_IRQn; // 中断通道:定时器3中断
nv.NVIC_IRQChannelPreemptionPriority=0; // 抢占优先级:0(数值越小优先级越高)
nv.NVIC_IRQChannelSubPriority=0; // 子优先级:0
nv.NVIC_IRQChannelCmd=ENABLE; // 使能该中断通道
NVIC_Init(&nv); // 应用配置到NVIC
}
void TIM3_IRQHandler(void) // 定时器3中断的入口函数(函数名固定,由启动文件定义)
{
if(TIM_GetFlagStatus(TIM3,TIM_FLAG_Update)==SET) // 检查是否是定时器更新事件触发的中断
{
TIM_ClearFlag(TIM3,TIM_FLAG_Update); // 清除更新事件标志位(必须手动清除,否则会持续触发中断)
currenttim++; // 每1ms触发一次中断,将时间计数器加1(实现毫秒计时)
}
}
void mt_delay(uint32_t ms)
{
uint32_t pre=currenttim+ms; // 计算目标时间(当前时间+要延时的毫秒数)
while(currenttim<pre); // 循环等待,直到currenttim达到目标时间(实现延时)
}
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); // 配置中断优先级分组为第2组(2位抢占优先级,2位子优先级)
tim3_init(); // 初始化定时器3(用于提供时间基准)
My_boardLED_Init(); // 初始化LED引脚
while(1) // 主循环(程序会一直在此循环中运行)
{
GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_SET); // 设置PC13引脚为高电平(原代码错误:两次均为高电平,无法闪烁)
mt_delay(500); // 延时500毫秒
GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_SET); // 再次设置PC13为高电平(逻辑错误)
mt_delay(100); // 延时100毫秒
}
}
实现呼吸灯
int main(void)
{
init(); // 初始化硬件配置
while(1) // 主循环,程序将一直运行
{
// 获取当前时间(秒级),假设GetTick()返回毫秒数
float t = GetTick() * 1.0e-3f;
// 计算占空比:生成0~1之间变化的正弦曲线
// sin()函数输出范围是-1~1,加1后变成0~2,乘以0.5后变成0~1
float duty = 0.5 * (sin(2 * 3.14 * t) + 1);
// 将占空比转换为定时器比较值(0~1000)
// 因为定时器周期设置为999,所以范围是0~1000
uint16_t ccrl = duty * 1000;
// 设置TIM1的通道1比较值,改变PWM占空比
TIM_SetCompare1(TIM1, ccrl);
}
}
void init(void)
{
GPIO_InitTypeDef in; // 定义GPIO初始化结构体
in.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出模式(用于PWM输出)
in.GPIO_Pin = GPIO_Pin_8; // 选择PA8引脚
in.GPIO_Speed = GPIO_Speed_2MHz; // 引脚速度为2MHz
GPIO_Init(GPIOA, &in); // 初始化GPIOA
in.GPIO_Pin = GPIO_Pin_13; // 选择PB13引脚
GPIO_Init(GPIOB, &in); // 初始化GPIOB
// 使能TIM1定时器时钟(TIM1在APB2总线上)
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
TIM_TimeBaseInitTypeDef tim; // 定义定时器基本结构体
tim.TIM_CounterMode = TIM_CounterMode_Up; // 向上计数模式
tim.TIM_Period = 999; // 自动重装载值(ARR),计数到999后重置
tim.TIM_Prescaler = 71; // 预分频值,72MHz/(71+1)=1MHz
tim.TIM_RepetitionCounter = 0; // 重复计数器(高级定时器特有,这里不用)
TIM_TimeBaseInit(TIM1, &tim); // 初始化定时器基本参数
// 使能ARR寄存器预加载功能
TIM_ARRPreloadConfig(TIM1, ENABLE);
// 启动定时器计数
TIM_Cmd(TIM1, ENABLE);
TIM_OCInitTypeDef oc; // 定义输出比较结构体
oc.TIM_OCMode = TIM_OCMode_PWM1; // PWM模式1:计数器<比较值时输出有效电平
oc.TIM_OCNPolarity = TIM_OCNPolarity_High; // 互补输出极性(高电平有效)
oc.TIM_OCPolarity = TIM_OCPolarity_High; // 主输出极性(高电平有效)
oc.TIM_OutputNState = TIM_OutputNState_Enable; // 使能互补输出
oc.TIM_OutputState = TIM_OutputState_Enable; // 使能主输出
oc.TIM_Pulse = 0; // 初始比较值(占空比0)
TIM_OC1Init(TIM1, &oc); // 初始化TIM1的通道1
// 使能TIM1的PWM输出(高级定时器特有,必须调用)
TIM_CtrlPWMOutputs(TIM1, ENABLE);
// 使能捕获比较预加载功能
TIM_CCPreloadControl(TIM1, ENABLE);
}
使用定时器进行超声波测距
#include "stm32f10x.h" // 确保包含正确的头文件
#include"delay.h"
#include<stdio.h>
#include"usart.h"
#include"usart.h"
void usart_init(void);
void tim_init(void);
int main(void)
{
usart_init();
tim_init(); // 初始化定时器,之前缺失
My_USART_SendString(USART1, "hello world\r\n");
while(1)
{
// 1. 向计数器写入0
TIM_SetCounter(TIM1, 0);
// 2. 清除捕获标志位
TIM_ClearFlag(TIM1, TIM_FLAG_CC1 | TIM_FLAG_CC2);
// 3. 开启定时器
TIM_Cmd(TIM1, ENABLE);
// 4. 向TRIG引脚发送10us脉冲
GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_SET);
DelayUs(10);
GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_RESET);
// 5. 等待上升沿捕获(回声开始)
uint32_t timeout = 0;
while(TIM_GetFlagStatus(TIM1, TIM_FLAG_CC1) == RESET)
{
DelayUs(1);
if(++timeout > 10000) // 超时处理,防止死等
{
break;
}
}
// 6. 等待下降沿捕获(回声结束)
timeout = 0;
while(TIM_GetFlagStatus(TIM1, TIM_FLAG_CC2) == RESET)
{
DelayUs(1);
if(++timeout > 50000) // 约5米测距上限
{
break;
}
}
// 7. 关闭定时器
TIM_Cmd(TIM1, DISABLE);
// 8. 计算距离
if(timeout <= 50000) // 未超时
{
uint16_t ccr1 = TIM_GetCapture1(TIM1); // 上升沿时间
uint16_t ccr2 = TIM_GetCapture2(TIM1); // 下降沿时间
uint32_t time_diff;
// 处理计数器溢出情况
if(ccr2 >= ccr1)
{
time_diff = ccr2 - ccr1;
}
else
{
time_diff = (65535 - ccr1) + ccr2;
}
// 计算距离:时间(us) * 声速(340m/s) / 2(往返)
float dis = time_diff * 0.034f / 2.0f;
My_USART_Printf(USART1, "dis=%.2f cm\r\n", dis);
}
else
{
My_USART_SendString(USART1, "Distance out of range\r\n");
}
Delay(100); // 测量间隔
}
}
void tim_init(void)
{
// 使能定时器1时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
// 定时器基本配置
TIM_TimeBaseInitTypeDef ti;
ti.TIM_CounterMode = TIM_CounterMode_Up;
ti.TIM_Period = 65535; // 最大计数
ti.TIM_Prescaler = 71; // 72MHz / (71+1) = 1MHz,计数频率1us
ti.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM1, &ti);
// 初始化ECHO引脚 PA8 (TIM1_CH1)
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef in;
in.GPIO_Mode = GPIO_Mode_IPD; // 下拉输入
in.GPIO_Pin = GPIO_Pin_8;
in.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &in);
// 初始化输入捕获通道1(上升沿)
TIM_ICInitTypeDef i;
i.TIM_Channel = TIM_Channel_1;
i.TIM_ICFilter = 6; // 增加滤波,减少干扰
i.TIM_ICPolarity = TIM_ICPolarity_Rising; // 上升沿捕获
i.TIM_ICPrescaler = TIM_ICPSC_DIV1;
i.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM_ICInit(TIM1, &i);
// 初始化输入捕获通道2(下降沿)
i.TIM_Channel = TIM_Channel_2;
i.TIM_ICFilter = 6;
i.TIM_ICPolarity = TIM_ICPolarity_Falling; // 下降沿捕获
i.TIM_ICPrescaler = TIM_ICPSC_DIV1;
i.TIM_ICSelection = TIM_ICSelection_IndirectTI; // 间接映射到TI1
TIM_ICInit(TIM1, &i);
// 初始化TRIG引脚 PA0
GPIO_InitTypeDef g;
g.GPIO_Mode = GPIO_Mode_Out_PP;
g.GPIO_Pin = GPIO_Pin_0;
g.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &g);
}
void usart_init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1, ENABLE);
// 配置USART1_TX (PA9)
GPIO_InitTypeDef in;
in.GPIO_Mode = GPIO_Mode_AF_PP;
in.GPIO_Pin = GPIO_Pin_9;
in.GPIO_Speed = GPIO_Speed_50MHz; // 提高速度
GPIO_Init(GPIOA, &in);
// 配置USART1_RX (PA10)
in.GPIO_Pin = GPIO_Pin_10;
in.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOA, &in);
// USART初始化参数
USART_InitTypeDef i;
i.USART_BaudRate = 115200;
i.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
i.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
i.USART_Parity = USART_Parity_No;
i.USART_StopBits = USART_StopBits_1;
i.USART_WordLength = USART_WordLength_8b;
USART_Init(USART1, &i);
USART_Cmd(USART1, ENABLE);
}
PWM捕获
#include "stm32f10x.h"
#include "delay.h"
#include "stdio.h"
#include "usart.h"
// 函数声明
void usart_init(void);
void tim3_init(void);
void tim1_init(void);
void My_USART_SendString(USART_TypeDef* USARTx, char* str);
void My_USART_Printf(USART_TypeDef* USARTx, const char* format, ...);
void Delay(uint32_t ms);
int main(void)
{
// 初始化外设
usart_init();
tim3_init(); // 初始化TIM3用于PWM输出
tim1_init(); // 初始化TIM1用于输入捕获
delay_init(); // 初始化延时函数
// 发送初始信息
My_USART_SendString(USART1, "你好世界\r\n");
// 设置TIM3的PWM占空比(周期1000,这里设置为20%)
TIM_SetCompare1(TIM3, 200);
while(1)
{
// 等待TIM1捕获到上升沿触发
while(TIM_GetFlagStatus(TIM1, TIM_FLAG_CC1) == RESET);
TIM_ClearFlag(TIM1, TIM_FLAG_CC1);
// 读取捕获值
uint16_t ccr1 = TIM_GetCapture1(TIM1); // 周期捕获值
uint16_t ccr2 = TIM_GetCapture2(TIM1); // 占空比捕获值
// 计算周期和占空比(定时器时钟为1MHz,所以1个计数单位=1us)
float period = ccr1 * 1.0e-3f; // 转换为ms
float duty = ((float)ccr2 / ccr1) * 100.0f;
// 串口输出结果
My_USART_Printf(USART1, "周期=%.3fms, 占空比=%.2f%%\r\n", period, duty);
// 延时500ms再进行下一次测量
Delay(500);
}
}
/**
* TIM1初始化:输入捕获模式,用于测量PWM信号的周期和占空比
* 通道1:上升沿捕获(测量周期)
* 通道2:下降沿捕获(测量占空比)
*/
void tim1_init(void)
{
// 使能TIM1和GPIOA时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1 | RCC_APB2Periph_GPIOA, ENABLE);
// 配置时基单元:72MHz / (71+1) = 1MHz,最大计数65535
TIM_TimeBaseInitTypeDef tim_base;
tim_base.TIM_CounterMode = TIM_CounterMode_Up;
tim_base.TIM_Period = 65535; // 最大计数
tim_base.TIM_Prescaler = 71; // 预分频,72MHz/72=1MHz
tim_base.TIM_ClockDivision = 0; // 时钟分割
tim_base.TIM_RepetitionCounter = 0; // 重复计数器(高级定时器特有)
TIM_TimeBaseInit(TIM1, &tim_base);
// 配置PA8为TIM1_CH1输入(上拉输入)
GPIO_InitTypeDef gpio;
gpio.GPIO_Mode = GPIO_Mode_IPU; // 上拉输入
gpio.GPIO_Pin = GPIO_Pin_8; // TIM1_CH1
gpio.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &gpio);
// 初始化输入捕获通道1(上升沿)
TIM_ICInitTypeDef tim_ic;
tim_ic.TIM_Channel = TIM_Channel_1;
tim_ic.TIM_ICFilter = 0x0F; // 较强滤波,减少噪声影响
tim_ic.TIM_ICPolarity = TIM_ICPolarity_Rising; // 上升沿捕获
tim_ic.TIM_ICPrescaler = TIM_ICPSC_DIV1; // 不分频
tim_ic.TIM_ICSelection = TIM_ICSelection_DirectTI; // 直接映射到TI1
TIM_ICInit(TIM1, &tim_ic);
// 初始化输入捕获通道2(下降沿)
tim_ic.TIM_Channel = TIM_Channel_2;
tim_ic.TIM_ICPolarity = TIM_ICPolarity_Falling; // 下降沿捕获
tim_ic.TIM_ICSelection = TIM_ICSelection_IndirectTI; // 间接映射到TI1
TIM_ICInit(TIM1, &tim_ic);
// 配置从模式:当捕获到上升沿时复位计数器
TIM_SelectInputTrigger(TIM1, TIM_TS_TI1FP1); // 选择TI1FP1作为触发源
TIM_SelectSlaveMode(TIM1, TIM_SlaveMode_Reset); // 触发时复位计数器
// 使能TIM1
TIM_Cmd(TIM1, ENABLE);
}
/**
* TIM3初始化:PWM输出模式,用于产生PWM信号
* 通道1输出PWM到PA6
*/
void tim3_init(void)
{
// 使能TIM3和GPIOA时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
// 配置时基单元:72MHz/(71+1) = 1MHz,周期1000→1kHz PWM
TIM_TimeBaseInitTypeDef tim_base;
tim_base.TIM_CounterMode = TIM_CounterMode_Up;
tim_base.TIM_Period = 999; // 周期=1000-1
tim_base.TIM_Prescaler = 71; // 预分频
tim_base.TIM_ClockDivision = 0;
TIM_TimeBaseInit(TIM3, &tim_base);
// 使能ARR预加载
TIM_ARRPreloadConfig(TIM3, ENABLE);
// 配置PA6为TIM3_CH1复用推挽输出
GPIO_InitTypeDef gpio;
gpio.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出
gpio.GPIO_Pin = GPIO_Pin_6; // TIM3_CH1
gpio.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &gpio);
// 配置PWM模式1
TIM_OCInitTypeDef tim_oc;
tim_oc.TIM_OCMode = TIM_OCMode_PWM1; // PWM模式1
tim_oc.TIM_OCPolarity = TIM_OCPolarity_High; // 输出极性高
tim_oc.TIM_OutputState = TIM_OutputState_Enable; // 使能输出
tim_oc.TIM_Pulse = 0; // 初始占空比0
TIM_OC1Init(TIM3, &tim_oc);
// 使能CCR1预加载
TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable);
// 使能TIM3
TIM_Cmd(TIM3, ENABLE);
}
/**
* USART1初始化:用于串口通信,仅发送模式
*/
void usart_init(void)
{
// 使能USART1和GPIOA时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
// 配置PA9为USART1_TX复用推挽输出
GPIO_InitTypeDef gpio;
gpio.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出
gpio.GPIO_Pin = GPIO_Pin_9; // USART1_TX
gpio.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &gpio);
// 配置USART1:115200波特率,8位数据,无校验,1个停止位
USART_InitTypeDef usart;
usart.USART_BaudRate = 115200;
usart.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
usart.USART_Mode = USART_Mode_Tx; // 仅发送模式
usart.USART_Parity = USART_Parity_No;
usart.USART_StopBits = USART_StopBits_1;
usart.USART_WordLength = USART_WordLength_8b;
USART_Init(USART1, &usart);
// 使能USART1
USART_Cmd(USART1, ENABLE);
}
// 串口发送一个字节
void My_USART_SendByte(USART_TypeDef* USARTx, uint8_t data)
{
while(USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET);
USART_SendData(USARTx, data);
while(USART_GetFlagStatus(USARTx, USART_FLAG_TC) == RESET);
}
// 串口发送字符串
void My_USART_SendString(USART_TypeDef* USARTx, char* str)
{
while(*str != '\0')
{
My_USART_SendByte(USARTx, *str++);
}
}
// 串口printf函数实现
#include <stdarg.h>
void My_USART_Printf(USART_TypeDef* USARTx, const char* format, ...)
{
char buffer[128];
va_list args;
va_start(args, format);
vsprintf(buffer, format, args);
va_end(args);
My_USART_SendString(USARTx, buffer);
}
使用ADC模拟信号(光敏控制板载led(常规序列
#include "stm32f10x.h"
#include "delay.h"
#include <stdio.h>
#include "usart.h"
void ADC1_init(void);
int main(void)
{
ADC1_init();
// 使能GPIOC时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_13;
// 改为推挽输出,无需外部上拉
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_Init(GPIOC, &GPIO_InitStruct);
while(1)
{
// 清除转换完成标志
ADC_ClearFlag(ADC1, ADC_FLAG_EOC);
// 启动软件转换
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
// 等待转换完成
while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);
// 读取转换值
uint16_t dr = ADC_GetConversionValue(ADC1);
// 计算电压值
float v = dr * (3.3f / 4095);
// 根据电压控制LED
if(v > 1.5f)
{
// 电压高于1.5V,LED亮
GPIO_WriteBit(GPIOC, GPIO_Pin_13, Bit_RESET);
}
else
{
// 电压低于等于1.5V,LED灭
GPIO_WriteBit(GPIOC, GPIO_Pin_13, Bit_SET);
}
// 可以添加适当延时,避免频繁转换
delay_ms(100);
}
}
void ADC1_init(void)
{
// 使能GPIOA时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
// 配置PA0为模拟输入
GPIO_InitTypeDef in;
in.GPIO_Pin = GPIO_Pin_0;
in.GPIO_Mode = GPIO_Mode_AIN; // 模拟输入模式
GPIO_Init(GPIOA, &in);
// 配置ADC时钟 (PCLK2/6 = 72MHz/6 = 12MHz)
RCC_ADCCLKConfig(RCC_PCLK2_Div6);
// 使能ADC1时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
// 初始化ADC
ADC_InitTypeDef adc;
adc.ADC_ContinuousConvMode = DISABLE; // 单次转换模式
adc.ADC_DataAlign = ADC_DataAlign_Right; // 右对齐
adc.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; // 无外部触发
adc.ADC_Mode = ADC_Mode_Independent; // 独立模式
adc.ADC_NbrOfChannel = 1; // 1个转换通道
adc.ADC_ScanConvMode = DISABLE; // 非扫描模式
ADC_Init(ADC1, &adc);
// 配置规则通道:通道0,序号1,采样时间13.5周期
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_13Cycles5);
// 关闭外部触发转换(我们使用软件触发)
ADC_ExternalTrigConvCmd(ADC1, DISABLE);
// 使能ADC1
ADC_Cmd(ADC1, ENABLE);
// 添加ADC校准步骤(重要)
ADC_ResetCalibration(ADC1);
while(ADC_GetResetCalibrationStatus(ADC1));
ADC_StartCalibration(ADC1);
while(ADC_GetCalibrationStatus(ADC1));
}
ADC捕捉电压变化
#include "stm32f10x.h" //
#include"delay.h"
#include<stdio.h>
#include"usart.h"
void usart_init(void);
void tim1_init(void);
void adc_init(void);
int main(void)
{
usart_init();
tim1_init();
adc_init();
My_USART_SendString(USART1,"hello");
while(1)
{
while(ADC_GetFlagStatus(ADC1,ADC_FLAG_JEOC)==RESET);
uint16_t jdr1=ADC_GetInjectedConversionValue(ADC1,ADC_InjectedChannel_1);
ADC_ClearFlag(ADC1,ADC_FLAG_JEOC);
float v=jdr1 *(3.3f/4095);
My_USART_Printf(USART1,"%.3f\n",v);
}
}
void adc_init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitTypeDef gpio={0};
gpio.GPIO_Mode=GPIO_Mode_AIN;
gpio.GPIO_Pin=GPIO_Pin_0;
GPIO_Init(GPIOA,&gpio);
//配置ADC模块时钟
RCC_ADCCLKConfig(RCC_PCLK2_Div6);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
//配置ADC基本参数
ADC_InitTypeDef adc={0};
adc.ADC_ContinuousConvMode=DISABLE;//不知
adc.ADC_DataAlign=ADC_DataAlign_Right;
adc.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;//不知
adc.ADC_Mode=ADC_Mode_Independent;//不知
adc.ADC_NbrOfChannel=1;
adc.ADC_ScanConvMode=DISABLE;
ADC_Init(ADC1,&adc);
//注入序列额外参数
ADC_InjectedSequencerLengthConfig(ADC1,1);
ADC_ExternalTrigInjectedConvConfig(ADC1,ADC_ExternalTrigInjecConv_T1_TRGO);
ADC_ExternalTrigInjectedConvCmd(ADC1,ENABLE);
ADC_InjectedChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_13Cycles5);
ADC_Cmd(ADC1,ENABLE);
}
void tim1_init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE);
TIM_TimeBaseInitTypeDef tim;
tim.TIM_CounterMode=TIM_CounterMode_Up;
tim.TIM_Period=999;
tim.TIM_Prescaler=71;
tim.TIM_RepetitionCounter=0;
TIM_TimeBaseInit(TIM1,&tim);
TIM_SelectOutputTrigger(TIM1,TIM_TRGOSource_Update);//TRGO:Update
TIM_Cmd(TIM1,ENABLE);
}
void usart_init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitTypeDef in={0};
in.GPIO_Pin=GPIO_Pin_9;
in.GPIO_Mode=GPIO_Mode_AF_PP;
in.GPIO_Speed=GPIO_Speed_2MHz;
GPIO_Init(GPIOA,&in);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
USART_InitTypeDef usa;
usa.USART_BaudRate=115200;
usa.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
usa.USART_Mode=USART_Mode_Tx;
usa.USART_Parity=USART_Parity_No;
usa.USART_StopBits=USART_StopBits_1;
usa.USART_WordLength=USART_WordLength_8b;
USART_Init(USART1,&usa);
USART_Cmd(USART1,ENABLE);
}

1040

被折叠的 条评论
为什么被折叠?



