STM32单片机学习_2
第七章ADC












因为采样的时候也需要时间, 但是这时候电压也在变化, 所以就要先断开采样, 去保持电压去量化

中间的就是应用于分压方法
1AD单通道
代码展示:
AD.c
void AD_Init(void)
{
//开启RCC时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_ADCCLKConfig(RCC_PCLK2_Div6);
//配置GPIO
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;//ADC专属模式
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//选择输入通道
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);
//配置ADC转换器
ADC_InitTypeDef ADC_InitStructure;
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;//如果ENABLE, 那么软件触发只要触发一次就可以了
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_InitStructure.ADC_NbrOfChannel = 1;
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
ADC_Init(ADC1, &ADC_InitStructure);
//开关控制+校准
ADC_Cmd(ADC1, ENABLE);
ADC_ResetCalibration(ADC1);
while(ADC_GetResetCalibrationStatus(ADC1) == SET);
ADC_StartCalibration(ADC1);
while(ADC_GetCalibrationStatus(ADC1) == SET);
}
uint16_t AD_GetValue(void)
{
ADC_SoftwareStartConvCmd(ADC1, ENABLE);//软件启动它
while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC) == RESET);//等待转换完成
return ADC_GetConversionValue(ADC1);
}
代码解释:

2AD多通道
这里因为没有学DMA所以不能去搞多连续转换, 因为只有当所有的通道搞完才会EOC标志位置0
那么解决办法就是使用单通道不扫描, 但是我们可以控制我们单次通道转换的到底是哪个通道
代码展示:
AD.c
void AD_Init(void)
{
//开启RCC时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_ADCCLKConfig(RCC_PCLK2_Div6);
//配置GPIO
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;//ADC专属模式
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//配置ADC转换器
ADC_InitTypeDef ADC_InitStructure;
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_InitStructure.ADC_NbrOfChannel = 1;
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
ADC_Init(ADC1, &ADC_InitStructure);
//开关控制+校准
ADC_Cmd(ADC1, ENABLE);
ADC_ResetCalibration(ADC1);
while(ADC_GetResetCalibrationStatus(ADC1) == SET);
ADC_StartCalibration(ADC1);
while(ADC_GetCalibrationStatus(ADC1) == SET);
}
uint16_t AD_GetValue(ADC_Channel)
{
//选择输入通道
ADC_RegularChannelConfig(ADC1, ADC_Channel, 1, ADC_SampleTime_55Cycles5);
ADC_SoftwareStartConvCmd(ADC1, ENABLE);//软件启动它
while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC) == RESET);//等待转换完成
return ADC_GetConversionValue(ADC1);
}
main.c
uint16_t AD0,AD1,AD2,AD3;
float Voltage;
int main(void)
{
OLED_Init();
AD_Init();
OLED_ShowString(1, 1, "AD0:");
OLED_ShowString(2, 1, "AD1:");
OLED_ShowString(3, 1, "AD2:");
OLED_ShowString(4, 1, "AD3:");
while (1)
{
AD0 = AD_GetValue(ADC_Channel_0);
AD1 = AD_GetValue(ADC_Channel_1);
AD2 = AD_GetValue(ADC_Channel_2);
AD3 = AD_GetValue(ADC_Channel_3);
OLED_ShowNum(1, 5, AD0, 4);
OLED_ShowNum(2, 5, AD1, 4);
OLED_ShowNum(3, 5, AD2, 4);
OLED_ShowNum(4, 5, AD3, 4);
Delay_ms(100);
}
}
代码解释:

这里就是每次转换前, 根据函数改变规则组
第八章DMA

存储器到存储器一般用软件触发, 外设和存储器之间一般用硬件触发
Flash是只读的


仲裁器:调度各个通道
AHB从设备:配置DMA参数
DMA请求:硬件触发DMA转运

数据宽度与对齐
DMA触发有三个条件, 传输计数器大于0, 触发源有触发信号, DMA使能
1DMA转运数据
代码展示:
MyDMA.c
uint16_t MyDMA_Size;
void MyDMA_Init(uint32_t AddrA, uint32_t AddrB, uint16_t Size)
{
MyDMA_Size = Size;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
DMA_InitTypeDef DMA_InitStructure;
DMA_InitStructure.DMA_PeripheralBaseAddr = AddrA;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable;
DMA_InitStructure.DMA_MemoryBaseAddr = AddrB;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_BufferSize = Size;//传输计数器
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_M2M = DMA_M2M_Enable;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
DMA_Init(DMA1_Channel1, &DMA_InitStructure);
//DMA_Cmd(DMA1_Channel1, ENABLE);
}
void MyDMA_Transfer(void)
{
DMA_Cmd(DMA1_Channel1, DISABLE);//先失能
DMA_SetCurrDataCounter(DMA1_Channel1, MyDMA_Size);
DMA_Cmd(DMA1_Channel1, ENABLE);
//等待转运完成
while(DMA_GetFlagStatus(DMA1_FLAG_TC1)==RESET);
DMA_ClearFlag(DMA1_FLAG_TC1);
}
main.c
uint8_t DataA[] = {0x01, 0x02, 0x03, 0x04};
uint8_t DataB[] = {0, 0 ,0, 0};
int main(void)
{
OLED_Init();
MyDMA_Init((uint32_t)DataA, (uint32_t)DataB, 4);
OLED_ShowString(1, 1, "DataA");
OLED_ShowString(3, 1, "DataB");
OLED_ShowHexNum(1, 8, (uint32_t)DataA, 8);
OLED_ShowHexNum(3, 8, (uint32_t)DataB, 8);
OLED_ShowHexNum(2, 1, DataA[0], 2);
OLED_ShowHexNum(2, 4, DataA[1], 2);
OLED_ShowHexNum(2, 7, DataA[2], 2);
OLED_ShowHexNum(2, 10, DataA[3], 2);
OLED_ShowHexNum(4, 1, DataB[0], 2);
OLED_ShowHexNum(4, 4, DataB[1], 2);
OLED_ShowHexNum(4, 7, DataB[2], 2);
OLED_ShowHexNum(4, 10, DataB[3], 2);
while (1)
{
DataA[0]++;
DataA[1]++;
DataA[2]++;
DataA[3]++;
OLED_ShowHexNum(2, 1, DataA[0], 2);
OLED_ShowHexNum(2, 4, DataA[1], 2);
OLED_ShowHexNum(2, 7, DataA[2], 2);
OLED_ShowHexNum(2, 10, DataA[3], 2);
OLED_ShowHexNum(4, 1, DataB[0], 2);
OLED_ShowHexNum(4, 4, DataB[1], 2);
OLED_ShowHexNum(4, 7, DataB[2], 2);
OLED_ShowHexNum(4, 10, DataB[3], 2);
Delay_ms(1000);
MyDMA_Transfer();
OLED_ShowHexNum(2, 1, DataA[0], 2);
OLED_ShowHexNum(2, 4, DataA[1], 2);
OLED_ShowHexNum(2, 7, DataA[2], 2);
OLED_ShowHexNum(2, 10, DataA[3], 2);
OLED_ShowHexNum(4, 1, DataB[0], 2);
OLED_ShowHexNum(4, 4, DataB[1], 2);
OLED_ShowHexNum(4, 7, DataB[2], 2);
OLED_ShowHexNum(4, 10, DataB[3], 2);
Delay_ms(1000);
}
}
代码解释:

这里的关键就是外设和存储器的基地址, 剩下的就是一系列配置
这里使软件使能
2DMA + AD 多通道
DMA是硬件触发, 触发源是ADC, ADC转化完成后触发DMA, 所以转运使在转换之后, 这里有ADC_DMA的函数, 调用后这个过程就是自动进行的
第一种使ADC单次扫描和DMA单次转换模式,(也就是注释的)
没有注释的就是自动扫描, 和DMA循环转换
代码展示:
AD.c
//SRAM数组
uint16_t AD_Value[4];
void AD_Init(void)
{
//开启RCC时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_ADCCLKConfig(RCC_PCLK2_Div6);
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
//配置GPIO
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;//ADC专属模式
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//现在4各通道全部搞开
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_55Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_55Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 4, ADC_SampleTime_55Cycles5);
//配置ADC转换器
ADC_InitTypeDef ADC_InitStructure;
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;//连续模式
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_InitStructure.ADC_NbrOfChannel = 4;
ADC_InitStructure.ADC_ScanConvMode = ENABLE;//连续模式
ADC_Init(ADC1, &ADC_InitStructure);
DMA_InitTypeDef DMA_InitStructure;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)AD_Value;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_BufferSize = 4;//传输计数器
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;//DMA循环模式
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
DMA_Init(DMA1_Channel1, &DMA_InitStructure);
DMA_Cmd(DMA1_Channel1, ENABLE);
//开启ADC到DMA的输出
ADC_DMACmd(ADC1, ENABLE);
//开关控制+校准
ADC_Cmd(ADC1, ENABLE);
ADC_ResetCalibration(ADC1);
while(ADC_GetResetCalibrationStatus(ADC1) == SET);
ADC_StartCalibration(ADC1);
while(ADC_GetCalibrationStatus(ADC1) == SET);
//连续转换和循环转运所以只要触发一次就行
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
}
//那么GetValue就不需要了
//void AD_GetValue(void)
//{
// //ADC是软件触发
// DMA_Cmd(DMA1_Channel1, DISABLE);//先失能
// DMA_SetCurrDataCounter(DMA1_Channel1, 4);
// DMA_Cmd(DMA1_Channel1, ENABLE);
//
// //等待DMA转运完成
// while(DMA_GetFlagStatus(DMA1_FLAG_TC1)==RESET);
// DMA_ClearFlag(DMA1_FLAG_TC1);
//}
main.c
int main(void)
{
OLED_Init();
AD_Init();
OLED_ShowString(1, 1, "AD0:");
OLED_ShowString(2, 1, "AD1:");
OLED_ShowString(3, 1, "AD2:");
OLED_ShowString(4, 1, "AD3:");
while (1)
{
//AD_GetValue();
OLED_ShowNum(1, 5, AD_Value[0], 4);
OLED_ShowNum(2, 5, AD_Value[1], 4);
OLED_ShowNum(3, 5, AD_Value[2], 4);
OLED_ShowNum(4, 5, AD_Value[3], 4);
Delay_ms(100);
}
}
代码解释:

第九章通信接口












起始位侦测就是对噪声的处理
对于printf在串口打印汉字出现乱码的情况有两种解决办法
1 keil和串口助手都选择UTF-8的编码格式, 同时keil加上--no-multibyte-chars才可以
2要么都使用GB开头的中文编码格式
下面是要用到的两个重要的寄存器

1串口发送
代码展示:
Serial.c
#include <stdio.h>
#include <stdarg.h>
void Serial_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate = 9600;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Tx;//接收和发送都需要的话就或
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_Init(USART1, &USART_InitStructure);
USART_Cmd(USART1, ENABLE);
}
void Serial_SendByte(uint8_t Byte)
{
//写入到TDR
USART_SendData(USART1, Byte);
//等待标志位, TXE为0的时候还没发送完成
while(USART_GetFlagStatus(USART1, USART_FLAG_TXE)==RESET);
}
void Serial_SendArray(uint8_t *Array, uint16_t Length)
{
uint16_t i;
for(i = 0;i<Length;i++)
{
Serial_SendByte(Array[i]);
}
}
void Serial_SendString(char *String)
{
uint16_t i;
for(i = 0; String[i] != '\0';i++)
{
Serial_SendByte(String[i]);
}
}
uint32_t Serial_Pow(uint32_t x, uint8_t y)
{
uint32_t ret = 1;
while(y--)
{
ret*=x;
}
return ret;
}
void Serial_SendNumber(uint32_t Num, uint8_t Length)
{
//这里的公式就是Num/10^i%10 + '0'
uint8_t i;
for(i = 0;i<Length;i++)
{
Serial_SendByte(Num/Serial_Pow(10, Length-1-i)%10 + '0');//发的字符
}
}
//printf重定向
int fputc(int ch, FILE *f)
{
Serial_SendByte(ch);
return ch;
}
//第三种方式重定向, 可变格式封装
void Serial_Printf(char *format, ...)
{
char String[100];
va_list arg;
va_start(arg, format);
vsprintf(String, format, arg);
va_end(arg);
Serial_SendString(String);
}
代码解释:
main 函数里面的操作
2串口发送+接收
可以查询的方式, 也可以中断的方式, 但是查询的方法使用于代码比较简单的程序
代码展示:
#include "stm32f10x.h" // Device header
#include <stdio.h>
#include <stdarg.h>
uint8_t Serial_RxData;
uint8_t Serial_RxFlag;
void Serial_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate = 9600;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;//接收和发送都需要的话就或
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_Init(USART1, &USART_InitStructure);
//开启中断
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
//分组
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
//NVIC通道初始化
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_Init(&NVIC_InitStructure);
USART_Cmd(USART1, ENABLE);
}
void Serial_SendByte(uint8_t Byte)
{
//写入到TDR
USART_SendData(USART1, Byte);
//等待标志位, TXE为0的时候还没发送完成
while(USART_GetFlagStatus(USART1, USART_FLAG_TXE)==RESET);
}
void Serial_SendArray(uint8_t *Array, uint16_t Length)
{
uint16_t i;
for(i = 0;i<Length;i++)
{
Serial_SendByte(Array[i]);
}
}
void Serial_SendString(char *String)
{
uint16_t i;
for(i = 0; String[i] != '\0';i++)
{
Serial_SendByte(String[i]);
}
}
uint32_t Serial_Pow(uint32_t x, uint8_t y)
{
uint32_t ret = 1;
while(y--)
{
ret*=x;
}
return ret;
}
void Serial_SendNumber(uint32_t Num, uint8_t Length)
{
//这里的公式就是Num/10^i%10 + '0'
uint8_t i;
for(i = 0;i<Length;i++)
{
Serial_SendByte(Num/Serial_Pow(10, Length-1-i)%10 + '0');//发的字符
}
}
//printf重定向
int fputc(int ch, FILE *f)
{
Serial_SendByte(ch);
return ch;
}
//第三种方式重定向, 可变格式封装
void Serial_Printf(char *format, ...)
{
char String[100];
va_list arg;
va_start(arg, format);
vsprintf(String, format, arg);
va_end(arg);
Serial_SendString(String);
}
uint8_t Serial_GetFlag()
{
if(Serial_RxFlag==1)
{
Serial_RxFlag = 0;
return 1;
}
else
return 0;
}
uint8_t Serial_GetRxData()
{
return Serial_RxData;
}
void USART1_IRQHandler(void)
{
if(USART_GetITStatus(USART1, USART_IT_RXNE)==SET)
{
//读取操作
Serial_RxData = USART_ReceiveData(USART1);
Serial_RxFlag = 1;
USART_ClearITPendingBit(USART1, USART_IT_RXNE);
}
}
代码解释:

USART_ITConfig, 这个函数就直接能够让收到数据的时候进入中断
一定要用好这个状态标志位, 主函数里面通过检查这个状态标志位, 来确定是不是有数据, 有数据直接掉函数得到数据
主函数:
3串口发送HEX文件包
我们一般发送数据是打包的,可以通过添加包头和包尾, 这样就可以将一段数据发送和接收
方便进行多字节的通信, 比如陀螺仪xyz发送的时候, 连续单字节发送很容易搞不清 哪个是头

文本数据包,基本不用担心包头包尾重复的问题

代码展示:
#include <stdio.h>
#include <stdarg.h>
uint8_t Serial_TxPacket[4];
uint8_t Serial_RxPacket[4];
uint8_t Serial_RxFlag;
.....
....
uint8_t Serial_GetFlag(void)
{
if(Serial_RxFlag==1)
{
Serial_RxFlag = 0;
return 1;
}
else
return 0;
}
void Serial_SendPacket(void)
{
Serial_SendByte(0xFF);
Serial_SendArray(Serial_TxPacket, 4);
Serial_SendByte(0xFE);
}
void USART1_IRQHandler(void)
{
static uint8_t RxState = 0;
static uint8_t pRxPacket = 0;//接收数据个数
if(USART_GetITStatus(USART1, USART_IT_RXNE)==SET)
{
uint8_t RxData = USART_ReceiveData(USART1);
if(RxState == 0)//这里可能会有这个数组里面存在两次的数据(搞混了, 太快导致)
{
if(RxData == 0xFF)
{
RxState = 1;
pRxPacket = 0;
}
}
else if(RxState == 1)
{
Serial_RxPacket[pRxPacket] = RxData;
pRxPacket++;
if(pRxPacket>=4)
{
RxState = 2;
}
}
else if(RxState == 2)
{
if(RxData == 0xFE)
{
RxState = 0;
Serial_RxFlag = 1;//置一个标志位
}
}
}
}
我们通过给状态机RxState 来代表数据到达了哪一个地方
代码解释:
4串口发送文本文件包
代码展示:
Serial.c
#include <stdio.h>
#include <stdarg.h>
char Serial_RxPacket[100];
uint8_t Serial_RxFlag;
//uint8_t Serial_GetFlag(void)
//{
// if(Serial_RxFlag==1)
// {
// Serial_RxFlag = 0;
// return 1;
// }
// else
// return 0;
//}
void USART1_IRQHandler(void)
{
static uint8_t RxState = 0;
static uint8_t pRxPacket = 0;//接收数据个数
if(USART_GetITStatus(USART1, USART_IT_RXNE)==SET)
{
uint8_t RxData = USART_ReceiveData(USART1);
if(RxState == 0)//这里可能会有这个数组里面存在两次的数据(搞混了, 太快导致)
{
if(RxData == '@' && Serial_RxFlag == 0)
{
RxState = 1;
pRxPacket = 0;
}
}
else if(RxState == 1)
{
if(RxData == '\r')
{
RxState = 2;
}
else
{
Serial_RxPacket[pRxPacket] = RxData;
pRxPacket++;
}
}
else if(RxState == 2)
{
if(RxData == '\n')
{
RxState = 0;
Serial_RxPacket[pRxPacket] = '\0';
Serial_RxFlag = 1;//置一个标志位
}
}
}
}
代码解释:
main.c

这里仍然是用状态机来完成, 数据包发送直接重定向printf发送就行, 关键是接收,
当发送的速度过快的时候, 可能会导致数据错乱, 在文本数据包里面这个问题就比较大了, 这里可以
加一个判断, 判断上一次结束才去接收数据 
那我们就不用Serial_GetFlag函数来判断接收到没, 可以直接extern声明一下, 当我们发送的数据完成的时候
这个标志位置1, 下一次数据才能被接收, 这样就很好解决了
openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。
更多推荐


所有评论(0)