一 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
|
|