关于配置STM32F1系列标准库外设时经常出现的问题,将所发现列在此文,持续更新

1.使能外设时钟时,会经常把APB1和APB2外设弄混,特别是喜欢copy代码改参数的时候,特别注意这件事,不然bug是发现不了的。

RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);

比如上面的ADC1时钟使能,你把APB1变成APB2,它是不会报错的。

2.使用标志位查询函数时,标志位未置位,意思就是事件没触发,其查询结果为0 RESET.只有触发了查询结果才是1 SET。所以这个搞混的话,也会死在程序内。标志位的清除需要根据手册决定,有的是读取某个寄存器就自动清楚了,有的要手动清除。

while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC)==RESET);

3.配置DMA串口输出模式的时候,在结构体配置中配置了要发送字节的长度,在开启一次DMA输出时就调用了这个长度,所以不仅要在结构体内配置,还要让开启一次DMA传输的函数能调用这个变量

DMA1_MEM_LEN=cndtr;这个一定要配置,或者是在下面开启DMA函数里里多加一个参数

#include "mydma.h"
DMA_InitTypeDef DMA_InitStructure;
u16 DMA1_MEM_LEN;
void MyDMA_Init(DMA_Channel_TypeDef* DMA_CHx,u32 cpar,u32 cmar,u16 cndtr)
{
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
    DMA_DeInit(DMA_CHx);
	
	DMA1_MEM_LEN=cndtr;//配置发送字节长度,不配置的话下面的开启一次DMA传输就是传了0个
    // 配置 DMA 初始化结构体的各个参数
    DMA_InitStructure.DMA_PeripheralBaseAddr =cpar /* 外设地址 */;
    DMA_InitStructure.DMA_MemoryBaseAddr =cmar /* 内存地址 */;
    DMA_InitStructure.DMA_DIR =DMA_DIR_PeripheralDST/* 数据传输方向,例如 DMA_DIR_PeripheralDST,表示从外设到内存 */;
    DMA_InitStructure.DMA_BufferSize = cndtr/* 数据传输的大小 */;
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable/* 外设地址是否增加 */;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable/* 内存地址是否增加 */;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte/* 外设数据大小 */;
    DMA_InitStructure.DMA_MemoryDataSize =DMA_MemoryDataSize_Byte /* 内存数据大小 */;
    DMA_InitStructure.DMA_Mode =DMA_Mode_Normal /* DMA模式,例如 DMA_Mode_Normal,表示正常模式 */;
    DMA_InitStructure.DMA_Priority = DMA_Priority_Medium/* DMA 通道的优先级 */;
    DMA_InitStructure.DMA_M2M =DMA_M2M_Disable /* 是否是内存到内存传输模式 */;

    // 初始化 DMA1 通道1
    DMA_Init(DMA_CHx, &DMA_InitStructure);

}
//开启一次 DMA 传输
void MyDMA_Enable(DMA_Channel_TypeDef* DMA_CHx)
{
	DMA_Cmd(DMA_CHx, DISABLE);
	DMA_SetCurrDataCounter(DMA_CHx,DMA1_MEM_LEN);
	DMA_Cmd(DMA_CHx, ENABLE);
}

4.IIC软件实现协议里,对于读取一个字节数据有很多方法。但是如下实现是有问题的

MyI2C_W_SCL(1);
temp|=MyI2C_R_SDA();
temp<<=1;
MyI2C_W_SCL(0);

高电平数据稳定,读取数据,看似是让temp读完数据之后,数据左移1位,到最后8次循环结束,最低位数据被移入最高位。假如第一次读到u8 SDA是0x01,temp=0x01, 左移1位-->temp=0x02

第二次读的是0x00,那结果是0x02.看着是没问题的 如果后面6个读的都是0,最后的结果就是

0x100,数据被移出去了。关键就在这里,为了让它最后得到的正确结果不被移出去,加一个判断,只有在0~6这7位的时候让它移位。

MyI2C_W_SCL(1);
temp|=MyI2C_R_SDA();
if(i<7)
temp<<=1;
MyI2C_W_SCL(0);

 我更推荐江科大的写法,简明易懂。让bit来移位,看的更清晰,接收的数据要做的就是接收这一个个有位置的bit。

if(MyI2C_R_SDA())
    temp|=(1<<(7-i));

5.关于老版正点原子战舰开发板(v2.3)(小黄鱼上买的图便宜,没发现版本太老了,但是能用就行)基本上是找不到它的资料,但是兼容性好,能找到原理图引脚位置就行。比如老版战舰在RS485实验时,需求的是PG9引脚来控制收发而V3以后都是PD7来控制收发,所以给出老板MCU引脚图

虽然不是很清晰,也能看个大概。 

改完引脚定义后就可以正常试验了,不改的话,它只能接收,不能发送

6.关于老版战舰版的AT24C02实验,接口是换了,原来是PB10,11.新版是PB6,7

引脚换完还要把IIC初始化内的模式改成开漏模式,PP模式没法使用。我举得还是配置上拉电阻使用开漏模式好使一点,用推挽还得一直换输入输出模式,很麻烦。

7.关于OV摄像头实验,SCCB协议跟IIC协议相比可能就差在电平跳变间隔时间和读时序上了。原来的电平跳变间隔个5us左右就够了,在SCCB里正点原子采用的是50us间隔。在读一个字节时,IIC是开始,写地址,读应答,写寄存器,读应答,开始,写地址+1,读数据,停止。而SCCB在其中第二个开始前要加一个停止信号,这是必须的。

8.关于FSMC外扩SRAM问题。这里开始我在想为什么LCD和SRAM可以同时运行?后面检索发现,ZET6单片机可以最多支持4路FSMC,他们的数据线,地址线这部分是公用的,片选线有4个。哪个被片选就用哪个。 

如这三个NE引脚。

9.关于解决老版战舰版SD卡实验读不到卡的问题,是因为老版战舰有两排跳线帽,一排是vcc,G8,D2...GND,第二排是SD卡相应的引脚,把跳线帽接到SD卡端即可解决。

  • 8
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值