打印
[应用相关]

STM32实验标准库代码

[复制链接]
259|4
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
tpgf|  楼主 | 2024-7-10 07:58 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
一 GPIO
1.1流水灯实验
#include "stm32f10x.h"
#include "Delay.h"
/*
        要求:LED进行闪烁
*/
int main(void)
{
        //2 声明一个GPIO_InitTypeDef类型的一个结构体 一般放函数最上面
        GPIO_InitTypeDef GPIOInitStruct;
        //1 使能时钟
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
        //3 对结构体进行赋值
        GPIOInitStruct.GPIO_Pin = GPIO_Pin_13;//指定引脚
        GPIOInitStruct.GPIO_Mode = GPIO_Mode_Out_OD;//开漏输出
        GPIOInitStruct.GPIO_Speed = GPIO_Speed_2MHz;///配置最大输出速度
        GPIO_Init(GPIOC, &GPIOInitStruct);//对IO进行初始化
       
    GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_SET);//开漏 1-熄灭,0-点亮
        GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_RESET);

        while(1)
        {
                GPIO_SetBits(GPIOC, GPIO_Pin_13);//向PC13脚写1
                Delay_ms(100);
                GPIO_ResetBits(GPIOC, GPIO_Pin_13);//向PC13脚写0
                Delay_ms(100);
        }
}



1.2按键实验
/*
        每按下一次按钮LED状态切换一次(按钮松开时)
*/
#include "stm32f10x.h"
int main(void)
{
        GPIO_InitTypeDef GPIOInitStruct;
        //PC13初始化 开漏输出
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
        GPIOInitStruct.GPIO_Pin = GPIO_Pin_13;
        GPIOInitStruct.GPIO_Mode = GPIO_Mode_Out_OD;
        GPIOInitStruct.GPIO_Speed = GPIO_Speed_2MHz;
        GPIO_Init(GPIOC, &GPIOInitStruct);
        //PAO初始化 设置为输入上拉模式
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
        GPIOInitStruct.GPIO_Pin = GPIO_Pin_0;
        GPIOInitStruct.GPIO_Mode = GPIO_Mode_IPU;
        GPIO_Init(GPIOA, &GPIOInitStruct);
    uint8_t current = 1;//标志位  默认一开始为高电平 按钮处于松开状态
        uint8_t previous = 1;//上次的值
    uint8_t LEDState = 1;//默认开漏输出高电平LED为熄灭状态
        while(1)
        {
                pre = current;
                if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) == GPIO_PIN_SET)//判断引脚电平是否处于高电平(按钮处于松开状态)
                {
                        current = 1;//高电平标志位(按钮松开)
                }
                else//按钮按下
                {
                        current = 0;//低电平标志(按钮按下)
                }
                if(pre != current)//捕捉到了按钮电平变化,需要进一步判断是按钮按下还是松开
                {
                        Delay_ms(10);//消抖
                        if(current == 0){}//按钮按下
                        else//按钮松开 需要切换LED状态
                        {
                                if(LEDState == 1)//LED是灭的
                                {
                                        HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_RESET);//点亮LED
                                        LEDState = 0;
                                }
                                else
                                {
                                        HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_SET);//熄灭LED
                                        LEDState = 1;
                                }
                        }
                }
  }
        }
}



二 外部中断
#include "stm32f10x.h"
/*
        要求:一个按键控制LED的亮另一个按键控制LED的灭
*/
int main(void)
{
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//选择中断优先级分组
        //1 按键初始化  将PC8(key4) PC9(key3)分别设置为输入上拉模式
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
        GPIO_InitTypeDef GPIOInitStruct;
        GPIOInitStruct.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;
        GPIOInitStruct.GPIO_Mode = GPIO_Mode_IPU;
        GPIO_Init(GPIOC,&GPIOInitStruct);
        //2配置EXTI引脚映射
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
        //PC8 --> EXTI8(key4 灭)        PC9        -->        EXTI9(亮)
        GPIO_EXTILineConfig(GPIO_PortSourceGPIOC,GPIO_PinSource8);
        GPIO_EXTILineConfig(GPIO_PortSourceGPIOC,GPIO_PinSource9);
        //3初始化EXTI
        //3.1初始化EXTI8
        EXTI_InitTypeDef        EXTIInitStruct;
        EXTIInitStruct.EXTI_Line        =        EXTI_Line8;
        EXTIInitStruct.EXTI_Mode        =        EXTI_Mode_Interrupt;
        EXTIInitStruct.EXTI_Trigger        =        EXTI_Trigger_Rising;//上升沿触发
        EXTIInitStruct.EXTI_LineCmd        =        ENABLE;
        EXTI_Init(&EXTIInitStruct);
        //3.2初始化EXTI9
        EXTIInitStruct.EXTI_Line        =        EXTI_Line9;
        EXTIInitStruct.EXTI_Mode        =        EXTI_Mode_Interrupt;
        EXTIInitStruct.EXTI_Trigger        =        EXTI_Trigger_Rising;
        EXTIInitStruct.EXTI_LineCmd        =        ENABLE;
        EXTI_Init(&EXTIInitStruct);
        //4初始化NVIC
        NVIC_InitTypeDef        NVICInitStruct;
        //4.1 EXTI8与EXTI9共用一个中断源
        NVICInitStruct.NVIC_IRQChannel        =        EXTI9_5_IRQn;
        NVICInitStruct.NVIC_IRQChannelPreemptionPriority        =        0;
        NVICInitStruct.NVIC_IRQChannelSubPriority        =        0;
        NVICInitStruct.NVIC_IRQChannelCmd        =        ENABLE;
        NVIC_Init(&NVICInitStruct);
        //5初始化LED PA8
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
        GPIOInitStruct.GPIO_Pin        =        GPIO_Pin_8;
        GPIOInitStruct.GPIO_Mode        =        GPIO_Mode_Out_OD;
        GPIOInitStruct.GPIO_Speed        =        GPIO_Speed_2MHz;
        GPIO_Init(GPIOA,&GPIOInitStruct);
       
        while(1)
        {

        }
}
void EXTI9_5_IRQHandler(void)
{
        if(EXTI_GetFlagStatus(EXTI_Line8)==SET)
        {
                //清除中断源
                EXTI_ClearITPendingBit(EXTI_Line8);
                //点灯
                GPIO_WriteBit(GPIOA,GPIO_Pin_8,Bit_RESET);
               
        }
        if(EXTI_GetFlagStatus(EXTI_Line9)==SET)
        {
                                //清除中断源
                EXTI_ClearITPendingBit(EXTI_Line9);
                //熄灯
                GPIO_WriteBit(GPIOA,GPIO_Pin_8,Bit_SET);
        }
}




三 串口
3.1简单串口发送数据
#include "stm32f10x.h"
#include<string.h>
/*
        使用串口的复用功能重映射功能
*/
int main(void)
{       
        //初始化TX PB6 AF_PP(复用推挽) 10MHZ
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
        GPIO_InitTypeDef GPIO_InitStructure;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
        GPIO_Init(GPIOB,&GPIO_InitStructure);
        //初始化RX PB7 IPU(输入上拉)
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
        GPIO_Init(GPIOB,&GPIO_InitStructure);
        //重映射USART1的TX RX引脚
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//开启AFIO的时钟
        GPIO_PinRemapConfig(GPIO_Remap_USART1,ENABLE);
        //使能USART1的时钟
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
        //设置USART1的参数
        USART_InitTypeDef USART1_InitTypeDef;
        USART1_InitTypeDef.USART_BaudRate = 9600;//波特率
        USART1_InitTypeDef.USART_WordLength = USART_WordLength_8b;//数据位
        USART1_InitTypeDef.USART_StopBits = USART_StopBits_1;
        USART1_InitTypeDef.USART_Parity = USART_Parity_No;//校验位
        USART1_InitTypeDef.USART_HardwareFlowControl =                       USART_HardwareFlowControl_None;
        USART1_InitTypeDef.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
        USART_Init(USART1,&USART1_InitTypeDef);
        //闭合USART1的总开关
        USART_Cmd(USART1,ENABLE);
    //发送单个字节
        //1.等待TDR寄存器清空
        while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET){}
        //2.写入要发送的数据
        USART_SendData(USART1,0x5a);
        //3.等待数据发送完成
        while(USART_GetFlagStatus(USART1,USART_FLAG_TC) == RESET){}
    //发送字节数组
        uint8_t arr[] = {0,1,2,3,4,5};
        for(uint32_t i=0;i<sizeof(arr)/sizeof(uint8_t);i++)
        {
                //1等待TDR寄存器清空(TXE置位置)
                while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET){}
                //2写入要发送的数据
                USART_SendData(USART1,arr);
        }
            //3等待数据发送完成
        while(USART_GetFlagStatus(USART1,USART_FLAG_TC) == RESET){}
    //发送字符
        while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET){}
        USART_SendData(USART1,'a');
        while(USART_GetFlagStatus(USART1,USART_FLAG_TC) == RESET){}
    //字符串
    const char *str = "hello world";
        for(uint32_t i=0;i<strlen(str);i++)
        {
                while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET){}
                USART_SendData(USART1,str);
        }
        while(USART_GetFlagStatus(USART1,USART_FLAG_TC) == RESET){}
        while(1)
        {
               
        }
}



3.2 简单串口接收数据
#include "stm32f10x.h"               
#include<string.h>
#include "LED.h"
/*
        要求:电脑发1点亮LED,发0熄灭LED
*/
int main(void)
{       
        //初始化TX PB6 AF_PP(复用推挽) 10MHZ
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
        GPIO_InitTypeDef GPIO_InitStructure;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
        GPIO_Init(GPIOB,&GPIO_InitStructure);
        //初始化RX PB7 IPU(输入上拉)
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
        GPIO_Init(GPIOB,&GPIO_InitStructure);
        //重映射USART1的TX RX引脚
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//开启AFIO的时钟
        GPIO_PinRemapConfig(GPIO_Remap_USART1,ENABLE);
        //使能USART1的时钟
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
        //设置USART1的参数
        USART_InitTypeDef USART1_InitTypeDef;
        USART1_InitTypeDef.USART_BaudRate = 9600;//波特率
        USART1_InitTypeDef.USART_WordLength = USART_WordLength_8b;//数据位
        USART1_InitTypeDef.USART_StopBits = USART_StopBits_1;
        USART1_InitTypeDef.USART_Parity = USART_Parity_No;//校验位
        USART1_InitTypeDef.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
        USART1_InitTypeDef.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
        USART_Init(USART1,&USART1_InitTypeDef);
        //闭合USART1的总开关
        USART_Cmd(USART1,ENABLE);
       
        LED_Init();       
        uint8_t c;
        while(1)
        {
                //等待RXNE寄存器置位
                while(USART_GetFlagStatus(USART1,USART_FLAG_RXNE)==RESET);
                //读取接收的字符
                c = USART_ReceiveData(USART1);
                if(c == '1')
                {
                        GPIO_ResetBits(GPIOC,GPIO_Pin_13);
                }
                else if(c == '0')
                {
                        GPIO_SetBits(GPIOC,GPIO_Pin_13);
                }
               
        }
}
       



3.3 串口中断接收数据
数据能够瞬间完成 就地处理

#include "stm32f10x.h"               
#include<string.h>
#include "LED.h"
int main(void)
{       
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//中断优先级分组
        //1初始化IO引脚  TX PB6 AF_PP(复用推挽) 10MHZ        RX PB7 IPU(输入上拉)
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
        GPIO_InitTypeDef GPIO_InitStructure;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
        GPIO_Init(GPIOB,&GPIO_InitStructure);

        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
        GPIO_Init(GPIOB,&GPIO_InitStructure);
        //2复用功能重映射 USART1的TX RX引脚
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//开启AFIO的时钟
        GPIO_PinRemapConfig(GPIO_Remap_USART1,ENABLE);
        //3使能USART1的时钟
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
        //4设置USART1的参数
        USART_InitTypeDef USART1_InitTypeDef;
        USART1_InitTypeDef.USART_BaudRate = 9600;//波特率
        USART1_InitTypeDef.USART_WordLength = USART_WordLength_8b;//数据位
        USART1_InitTypeDef.USART_StopBits = USART_StopBits_1;
        USART1_InitTypeDef.USART_Parity = USART_Parity_No;//校验位
        USART1_InitTypeDef.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
        USART1_InitTypeDef.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
        USART_Init(USART1,&USART1_InitTypeDef);
        //5配置中断源
        USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
        NVIC_InitTypeDef NVICInitStruct;
        NVICInitStruct.NVIC_IRQChannel = USART1_IRQn;
        NVICInitStruct.NVIC_IRQChannelPreemptionPriority = 0;
        NVICInitStruct.NVIC_IRQChannelSubPriority = 0;
        NVICInitStruct.NVIC_IRQChannelCmd = ENABLE;
        NVIC_Init(&NVICInitStruct);
        //6闭合USART1的总开关
        USART_Cmd(USART1,ENABLE);
       
        LED_Init();       
       
        while(1)
        {

        }
}
void USART1_IRQHandler(void)
{       
        uint8_t c;
        if(USART_GetITStatus(USART1, USART_IT_RXNE) == SET)
  {
                // 清除中断,读取数据
                c = USART_ReceiveData(USART1);
               
                if(c=='0')
    {
                        // 熄灯
                        GPIO_WriteBit(GPIOC, GPIO_Pin_13, Bit_SET);
                }
                else if(c=='1')
                {
                        //亮灯
                        GPIO_WriteBit(GPIOC, GPIO_Pin_13, Bit_RESET);
                }
        }
}




数据处理耗时较长 延迟处理

#include "stm32f10x.h"
#include "queue.h"
#include <string.h>

static Queue_HandleTypeDef hQueue;//定义句柄

static void USART_Echo_Init(void);
static void USART_Echo_Proc(void);
static void USART1_SendString(const char *Str);

int main(void)
{
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//中断优先级分组 一般固定放在这个位置
       
        USART_Echo_Init();
       
        while(1)
        {
                USART_Echo_Proc();
        }
}

static void USART_Echo_Init(void)
{
        GPIO_InitTypeDef GPIOInitStruct;
       
        Queue_Init(&hQueue);//队列初始化放在中断开启前
       
        // 1. 初始化IO引脚
        // PB6 PB7
        // Tx
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
        GPIOInitStruct.GPIO_Pin = GPIO_Pin_6;
        GPIOInitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
        GPIOInitStruct.GPIO_Speed = GPIO_Speed_10MHz;
        GPIO_Init(GPIOB, &GPIOInitStruct);
        // Rx
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
        GPIOInitStruct.GPIO_Pin = GPIO_Pin_7;
        GPIOInitStruct.GPIO_Mode = GPIO_Mode_IPU;
        GPIO_Init(GPIOB, &GPIOInitStruct);
        // AFIO
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
        GPIO_PinRemapConfig(GPIO_Remap_USART1, ENABLE);
       
        // 2. 使能USART1的时钟
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
       
        // 3. 配置USART1的参数
        USART_InitTypeDef USARTInitStruct;
        USARTInitStruct.USART_BaudRate = 9600;
        USARTInitStruct.USART_WordLength = USART_WordLength_8b;
        USARTInitStruct.USART_Parity = USART_Parity_No;
        USARTInitStruct.USART_StopBits = USART_StopBits_1;
        USARTInitStruct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
        USARTInitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
        USART_Init(USART1, &USARTInitStruct);
       
        // 4. 配置中断
        USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
       
        NVIC_InitTypeDef NVICInitStruct;
        NVICInitStruct.NVIC_IRQChannel = USART1_IRQn;
        NVICInitStruct.NVIC_IRQChannelPreemptionPriority = 0;
        NVICInitStruct.NVIC_IRQChannelSubPriority = 0;
        NVICInitStruct.NVIC_IRQChannelCmd = ENABLE;
        NVIC_Init(&NVICInitStruct);
       
        // 5. 闭合USART1的总开关
        USART_Cmd(USART1, ENABLE);
}

void USART1_IRQHandler(void)//一旦有数据传输就会触发中断
{
        uint8_t c;
        if(USART_GetITStatus(USART1, USART_IT_RXNE) == SET)//判断中断来源
        {
                c = USART_ReceiveData(USART1);//读取数据
               
                Queue_Enqueue(&hQueue, c);//入队
        }
}

static uint8_t a[100];//数据接收缓冲数组
static uint16_t cursor = 0; //游标

static void USART_Echo_Proc(void)//数据缓冲区处理数据
{
        uint8_t c;
       
        USART_ITConfig(USART1, USART_IT_RXNE, DISABLE);//禁止中断
        ErrorStatus error = Queue_Dequeue(&hQueue, &c);//出队
        USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//使能中断
       
        if(error == SUCCESS)
        {
                a[cursor++] = c;//将读取的值存入数组
               
                if(cursor>2 && a[cursor-2] == '\r'&& a[cursor - 1] == '\n') // 收到新行
                {
                        // 发送出去
                        a[cursor] = 0;// \r\n\0
                        USART1_SendString((const char *)a);//发送数据
                        cursor=0;
                }
        }
}

static void USART1_SendString(const char *Str)
{
        uint32_t i;
        for(i=0;i<strlen(Str);i++)
        {
                while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); // 等待发送数据寄存器清空
                USART_SendData(USART1, Str);
        }
        while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
}




//队列封装
#include "queue.h"

void Queue_Init(Queue_HandleTypeDef *hQueue)//初始化
{
        hQueue->Tail = 0;
}

void Queue_Enqueue(Queue_HandleTypeDef *hQueue, uint8_t Element)//入队
{
        hQueue->Data[hQueue->Tail ++] = Element;
}

ErrorStatus Queue_Dequeue(Queue_HandleTypeDef *hQueue, uint8_t *pElement)//出队
{
        uint32_t i;
        if(hQueue->Tail == 0) return ERROR; // 队列空,操作无效
        *pElement = hQueue->Data[0];
        for(i=0;i<hQueue->Tail-1;i++)
        {
                hQueue->Data = hQueue->Data[i+1];//Tail左移
        }
        hQueue->Tail--;
        return SUCCESS;
}




#ifndef _QUEUE_H_
#define _QUEUE_H_

#include "stm32f10x.h"

typedef struct
{
        uint8_t Data[100];
        uint16_t Tail; // 队尾
} Queue_HandleTypeDef;

void Queue_Init(Queue_HandleTypeDef *hQueue);
void Queue_Enqueue(Queue_HandleTypeDef *hQueue, uint8_t Element);
ErrorStatus Queue_Dequeue(Queue_HandleTypeDef *hQueue, uint8_t *pElement);

#endif // 防止头文件被重复引用




3.4 串口中断发送数据
#include "stm32f10x.h"
#include "queue.h"
#include <string.h>

static Queue_HandleTypeDef hQueue;

static void USART_Tx_Init(void);
static void USART_SendString(const char *Str);

int main(void)
{
        USART_Tx_Init();
       
        USART_SendString("Hello world\r\n");
       
        USART_SendString("I love stm32\r\n");
       
        while(1){}
}

void USART1_IRQHandler(void)
{
        uint8_t c;
       
        if(USART_GetITStatus(USART1, USART_IT_TXE) == SET)//判断中断来源
        {
                if(Queue_Dequeue(&hQueue, &c) == SUCCESS)//出队成功
                {
                        USART_SendData(USART1, c);//发送
                }
                else//出队失败
                {
                        USART_ITConfig(USART1, USART_IT_TXE, DISABLE);//关闭中断
                }
        }
}

static void USART_SendString(const char *Str)//发送处理函数
{
        uint32_t i;
        USART_ITConfig(USART1, USART_IT_TXE, DISABLE);//关闭中断
        for(i=0;i<strlen(Str);i++)
        {
                Queue_Enqueue(&hQueue, Str);//入队
        }
        USART_ITConfig(USART1, USART_IT_TXE, ENABLE);//开启中断
}

static void USART_Tx_Init(void)
{
        GPIO_InitTypeDef GPIOInitStruct;
       
        Queue_Init(&hQueue);//队列初始化
       
        // 1. 初始化IO引脚
        // PB6 PB7
        // Tx
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
        GPIOInitStruct.GPIO_Pin = GPIO_Pin_6;
        GPIOInitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
        GPIOInitStruct.GPIO_Speed = GPIO_Speed_10MHz;
        GPIO_Init(GPIOB, &GPIOInitStruct);
        // Rx
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
        GPIOInitStruct.GPIO_Pin = GPIO_Pin_7;
        GPIOInitStruct.GPIO_Mode = GPIO_Mode_IPU;
        GPIO_Init(GPIOB, &GPIOInitStruct);
        // AFIO
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
        GPIO_PinRemapConfig(GPIO_Remap_USART1, ENABLE);
       
        // 2. 使能USART1的时钟
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
       
        // 3. 配置USART1的参数
        USART_InitTypeDef USARTInitStruct;
        USARTInitStruct.USART_BaudRate = 9600;
        USARTInitStruct.USART_WordLength = USART_WordLength_8b;
        USARTInitStruct.USART_Parity = USART_Parity_No;
        USARTInitStruct.USART_StopBits = USART_StopBits_1;
        USARTInitStruct.USART_Mode = USART_Mode_Tx;
        USARTInitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
        USART_Init(USART1, &USARTInitStruct);
       
        // 4. 配置中断
        // USART_ITConfig(USART1, USART_IT_TXE, ENABLE);
       
        NVIC_InitTypeDef NVICInitStruct;
        NVICInitStruct.NVIC_IRQChannel = USART1_IRQn;
        NVICInitStruct.NVIC_IRQChannelPreemptionPriority = 0;
        NVICInitStruct.NVIC_IRQChannelSubPriority = 0;
        NVICInitStruct.NVIC_IRQChannelCmd = ENABLE;
        NVIC_Init(&NVICInitStruct);
       
        // 5. 闭合USART1的总开关
        USART_Cmd(USART1, ENABLE);
}




四 IIC
4.1 主机数据发送与接收
#include "stm32f10x.h"
static void App_I2C_Init(void);
static ErrorStatus App_I2C_MasterTransmit(uint8_t SlaveAddr, const uint8_t *pData, uint16_t Size);
static ErrorStatus App_I2C_MasterReceive(uint8_t SlaveAddr, uint8_t *pDataOut, uint16_t Size);


int main(void)
{
        uint8_t oled_init_command[] = {
                0x00, // Command Stream
                0xa8, 0x3f, // Set MUX Ratio
                0xd3, 0x00, // Set Display Offset
                0x40, // Set Display Start Line
                0xa0, // Set Segment re-map
                0xc0, // Set COM Output Scan Direction
                0xda, 0x02, // Set COM Pins hardware configuration
                0x81, 0x7f, // Set Contrast Control
                0xa5, // Enable Entire Display On
                0xa6, // Set Normal Display
                0xd5, 0x80, // Set OSC Frequency
                0x8d, 0x14, // Enable charge pump regulator
                0xaf, // Display on
        };
       
        uint8_t oled_off_command[] = { 0x00, 0xae};//熄灭屏幕
        uint8_t oled_on_command[] = { 0x00, 0xaf};//点亮屏幕
       
        uint8_t buffer[8];//声明接收缓冲区 最多读8个字节
    App_I2C_Init();
    App_I2C_MasterTransmit(0x78,oled_init_command,sizeof(oled_init_command)/sizeof(uint8_t));//发送OLED命令
    //熄灭显示器
    App_I2C_MasterTransmit(0x78,oled_off_command,sizeof(oled_off_command)/sizeof(uint8_t));
    App_I2C_MasterReceive(0x78, buffer,1);//从屏幕读取数据
    App_I2C_MasterReceive(0x78, buffer,2);
    App_I2C_MasterReceive(0x78, buffer,8);
    //点亮显示器
    App_I2C_MasterTransmit(0x78,oled_off_command,sizeof(oled_on_command)/sizeof(uint8_t));
    App_I2C_MasterReceive(0x78, buffer,1);
    App_I2C_MasterReceive(0x78, buffer,2);
    App_I2C_MasterReceive(0x78, buffer,8);
       
        while(1)
        {
        }
}

static void App_I2C_Init(void)//初始化
{
        // #1. 初始化SCL和SDA引脚
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
       
        GPIO_InitTypeDef GPIO_InitStruct;
        GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
        GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_OD;
        GPIO_InitStruct.GPIO_Speed = GPIO_Speed_10MHz;
        GPIO_Init(GPIOB, &GPIO_InitStruct);
       
        // #2. 开启I2C的时钟并复位
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
        RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1, ENABLE);
        RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1, DISABLE);
       
        // #3. 设置I2C的参数
        I2C_InitTypeDef I2C_InitStruct;
       
        I2C_InitStruct.I2C_Mode = I2C_Mode_I2C;
        I2C_InitStruct.I2C_ClockSpeed = 400000;
        I2C_InitStruct.I2C_DutyCycle = I2C_DutyCycle_2;
       
        I2C_Init(I2C1, &I2C_InitStruct);
       
        // #4. 使能I2C
        I2C_Cmd(I2C1, ENABLE);
}

static ErrorStatus App_I2C_MasterTransmit(uint8_t SlaveAddr, const uint8_t *pData, uint16_t Size)//数据发送函数
{
        ErrorStatus ret = SUCCESS;
       
        // #1. 等待总线空闲
        while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY) == SET);
        // #2. 发送起始位
        I2C_GenerateSTART(I2C1, ENABLE);
        while(I2C_GetFlagStatus(I2C1, I2C_FLAG_SB) == RESET);
        // #3. 发送地址
        I2C_ClearFlag(I2C1, I2C_FLAG_AF);
        I2C_SendData(I2C1, SlaveAddr & 0xfe);
       
        while(I2C_GetFlagStatus(I2C1, I2C_FLAG_ADDR) == RESET)
        {
                if(I2C_GetFlagStatus(I2C1, I2C_FLAG_AF) == SET)
                {
                        ret = ERROR;
                        goto STOP;
                }
        }
       
        // #4. 发送数据
        I2C_ReadRegister(I2C1, I2C_Register_SR1); // 清除ADDR
        I2C_ReadRegister(I2C1, I2C_Register_SR2);
       
        uint32_t i;
       
        for(i=0;i<Size;i++)
        {
                while(I2C_GetFlagStatus(I2C1, I2C_FLAG_TXE) == RESET)
                {
                        if(I2C_GetFlagStatus(I2C1, I2C_FLAG_AF) == SET)
                        {
                                ret = ERROR;
                                goto STOP;
                        }
                }
                I2C_SendData(I2C1, pData);
        }
       
        while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BTF) == RESET)
        {
                if(I2C_GetFlagStatus(I2C1, I2C_FLAG_AF) == SET)
                {
                        ret = ERROR;
                        goto STOP;
                }
        }
       
        // #5. 发送停止位
STOP:
        I2C_GenerateSTOP(I2C1, ENABLE);
        while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY) == SET);
       
        return ret;
}

static ErrorStatus App_I2C_MasterReceive(uint8_t SlaveAddr, uint8_t *pDataOut, uint16_t Size)//数据接收函数
{
        // #1. 等待总线空闲
        while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY) == SET);
       
        // #2. 发送起始位
        I2C_GenerateSTART(I2C1, ENABLE);
       
        while(I2C_GetFlagStatus(I2C1, I2C_FLAG_SB) == RESET);
       
        // #3. 发送从机地址
        I2C_ClearFlag(I2C1, I2C_FLAG_AF);
       
        I2C_SendData(I2C1, SlaveAddr | 0x01);
       
        while(I2C_GetFlagStatus(I2C1, I2C_FLAG_ADDR) == RESET)
        {
                if(I2C_GetFlagStatus(I2C1, I2C_FLAG_AF) == SET)
                {
                        I2C_GenerateSTOP(I2C1, ENABLE);
                        while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY) == SET);
                       
                        return ERROR;
                }
        }
       
        // #4. 接收数据
        if(Size == 1)//只有一个字节时
        {
                // 4.1. 清除ADDR标志位
                I2C_ReadRegister(I2C1, I2C_Register_SR1);
                I2C_ReadRegister(I2C1, I2C_Register_SR2);
               
                // 4.2. ACK=0, STOP=1
                I2C_AcknowledgeConfig(I2C1, DISABLE);
                I2C_GenerateSTOP(I2C1, ENABLE);
               
                // 4.3. 等待RXNE,然后把数据读出来
                while(I2C_GetFlagStatus(I2C1, I2C_FLAG_RXNE) == RESET);
               
                pDataOut[0] = I2C_ReceiveData(I2C1);
               
                while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY) == SET);
               
                return SUCCESS;
        }
        else if(Size == 2)//只有两个字节时
        {
                I2C_AcknowledgeConfig(I2C1, ENABLE);
               
                // 4.1. 清除ADDR标志位
                I2C_ReadRegister(I2C1, I2C_Register_SR1);
                I2C_ReadRegister(I2C1, I2C_Register_SR2);
               
                // 4.2. 等待RXNE=1
                while(I2C_GetFlagStatus(I2C1, I2C_FLAG_RXNE) == RESET);
                I2C_AcknowledgeConfig(I2C1, DISABLE);
                I2C_GenerateSTOP(I2C1, ENABLE);
                pDataOut[0] = I2C_ReceiveData(I2C1);
               
                // 4.3. 接收第2个字节
                while(I2C_GetFlagStatus(I2C1, I2C_FLAG_RXNE) == RESET);
                pDataOut[1] = I2C_ReceiveData(I2C1);
               
                // 4.4. 等待总线空闲
                while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY) == SET);
               
                return SUCCESS;
        }
        else if(Size > 2)//字节数大于2
        {
                // ACK = 1 N-1 ACK NAK
                I2C_AcknowledgeConfig(I2C1, ENABLE);
               
                // 4.1. 清除ADDR标志位
                I2C_ReadRegister(I2C1, I2C_Register_SR1);
                I2C_ReadRegister(I2C1, I2C_Register_SR2);
               
                // 4.2.
                uint32_t i;
                for(i=0;i<Size-3;i++)
                {
                        while(I2C_GetFlagStatus(I2C1, I2C_FLAG_RXNE) == RESET);
                       
                        pDataOut = I2C_ReceiveData(I2C1);
                }
               
                // 4.3. 等待BTF标志位置位
                while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BTF) == RESET);
               
                pDataOut[Size-3] = I2C_ReceiveData(I2C1);
                pDataOut[Size-2] = I2C_ReceiveData(I2C1);
               
                // 4.4. ACK=0,STOP=1
                I2C_AcknowledgeConfig(I2C1, DISABLE);
                I2C_GenerateSTOP(I2C1, ENABLE);
               
                // 4.5. 等待RXNE标志位置位
                pDataOut[Size-1] = I2C_ReceiveData(I2C1);
               
                // 4.6. 等待总线空闲
                while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY) == SET);
               
                return SUCCESS;
        }
        else
        {
                return ERROR;
        }
}


————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/m0_73843839/article/details/140305401

使用特权

评论回复
沙发
micoccd| | 2024-7-10 10:28 | 只看该作者
我还是喜欢标准库,HAL太臃肿了,执行效率不行

使用特权

评论回复
板凳
sfd123| | 2024-7-10 12:04 | 只看该作者
一直用 标准库!

使用特权

评论回复
地板
回复就哭哭| | 2024-7-31 23:48 | 只看该作者
标准库虽然在STM32的开发中逐渐被HAL库和LL库所取代,但它仍然是学习和理解STM32硬件操作的一个良好起点。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

1660

主题

14870

帖子

10

粉丝