CRC循环冗余实验是利用STM32内部的CRC校验电路对数组中数进行CRC校验。然后将CRC校验码通过USART1(PA9,PA10)在串口助手上显示出来。
关于代码部分就很简单了,CRC配置部分,只需要打开CRC的时钟就可以了。
void CRC_Config(void)
{
/* Enable CRC clock */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_CRC, ENABLE);
}
主函数部分,就是将数组中的数据送给CRC就可以了
int main(void)
{
u8 i = 0;
/* config the sysclock to 72M */
RCC_Configuration();
/* USART1 config */
USART1_Config();
/* 使能CRC时钟 */
CRC_Config();
printf("\r\n 这是一个 CRC(循环冗余校验)实验 \r\n");
/* Compute the CRC of "DataBuffer" */
for(i=0; i<BUFFER_SIZE; i++ )
{
CRCValue = CRC_CalcBlockCRC((uint32_t *)DataBuffer, BUFFER_SIZE);
printf("\r\n32-bit CRC 校验码为:0X%X\r\n", CRCValue);
}
printf("\r\nCRC(循环冗余校验)测试成功\r\n");
while (1)
{
}
}
每个芯片都有唯一的ID,就如同每个网卡都有唯一的MAC地址一样,本实验就是读取自己的STM32F103ZET的ID号。如下图所示,大家可以看见我的芯片ID号:
这里给出获取ID号的函数,其实就是获得固定地址(这个地址就是ID号的地址)中的数据。然后调用串口发送程序,也就发送ID到串口助手上显示。
void Get_ChipID(void)
{
ChipUniqueID[0] = *(__IO u32 *)(0X1FFFF7F0); // 高字节
ChipUniqueID[1] = *(__IO u32 *)(0X1FFFF7EC); //
ChipUniqueID[2] = *(__IO u32 *)(0X1FFFF7E8); // 低字节
}
ADC模数转换实验,当初自己搞起来不是很顺手,后来移植野火的例程,看了一遍工作过程,还是比较简单的,主要就是配置工作方式。因为手头上没有合适的外部模拟信号,这里我仅仅给定了0V和3.3V的电源输入。然后,将转换后的数字数据输出到串口助手上面。
下面附上ADC的配置代码,如下:
/*
* 函数名:ADC1_GPIO_Config
* 描述 :使能ADC1和DMA1的时钟,初始化PC.01
* 输入 : 无
* 输出 :无
* 调用 :内部调用
*/
static void ADC1_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* Enable DMA clock */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
/* Enable ADC1 and GPIOC clock */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOC, ENABLE);
/* Configure PC.01 as analog input */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOC, &GPIO_InitStructure); // PC1,输入时不用设置速率
}
/* 函数名:ADC1_Mode_Config
* 描述 :配置ADC1的工作模式为MDA模式
* 输入 : 无
* 输出 :无
* 调用 :内部调用
*/
static void ADC1_Mode_Config(void)
{
DMA_InitTypeDef DMA_InitStructure;
ADC_InitTypeDef ADC_InitStructure;
/* DMA channel1 configuration */
DMA_DeInit(DMA1_Channel1);
DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;
DMA_InitStructure.DMA_MemoryBaseAddr = (u32)&ADC_ConvertedValue;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_BufferSize = 1;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel1, &DMA_InitStructure);
/* Enable DMA channel1 */
DMA_Cmd(DMA1_Channel1, ENABLE);
/* ADC1 configuration */
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_InitStructure.ADC_ScanConvMode = ENABLE;
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfChannel = 1;
ADC_Init(ADC1, &ADC_InitStructure);
/* ADC1 regular channel11 configuration */
ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 1, ADC_SampleTime_55Cycles5);
/* Enable ADC1 DMA */
ADC_DMACmd(ADC1, ENABLE);
/* Enable ADC1 */
ADC_Cmd(ADC1, ENABLE);
/* Enable ADC1 reset calibaration register */
ADC_ResetCalibration(ADC1);
/* Check the end of ADC1 reset calibration register */
while(ADC_GetResetCalibrationStatus(ADC1));
/* Start ADC1 calibaration */
ADC_StartCalibration(ADC1);
/* Check the end of ADC1 calibration */
while(ADC_GetCalibrationStatus(ADC1));
/* Start ADC1 Software Conversion */
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
}
PWM波形发生,就是利用TIMx来实现的。这里本实验使用定时器TIM3产生四路PWM波输出。使用的四路输出通道是:
PA.06: (TIM3_CH1)
PA.07: (TIM3_CH2)
PB.00: (TIM3_CH3)
PB.01: (TIM3_CH4)
由于我手头现在没有示波器,现在去实验室借用示波器来演示的话,也来不及了,也就使用MDK软件模拟仿真吧。
下面附上TIM3的配置代码,这里是参考野火的例程。
/*
* 函数名:TIM3_GPIO_Config
* 描述 :配置TIM3复用输出PWM时用到的I/O
* 输入 :无
* 输出 :无
* 调用 :内部调用
*/
static void TIM3_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* TIM3 clock enable */
//PCLK1经过2倍频后作为TIM3的时钟源等于36MHz
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
/* GPIOA and GPIOB clock enable */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE);
/*GPIOA Configuration: TIM3 channel 1 and 2 as alternate function push-pull */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/*GPIOB Configuration: TIM3 channel 3 and 4 as alternate function push-pull */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
/*
* 函数名:TIM3_Mode_Config
* 描述 :配置TIM3输出的PWM信号的模式,如周期、极性、占空比
* 输入 :无
* 输出 :无
* 调用 :内部调用
*/
static void TIM3_Mode_Config(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
/* PWM信号电平跳变值 */
u16 CCR1_Val = 500;
u16 CCR2_Val = 375;
u16 CCR3_Val = 250;
u16 CCR4_Val = 125;
/* -----------------------------------------------------------------------
TIM3 Configuration: generate 4 PWM signals with 4 different duty cycles:
TIM3CLK = 36 MHz, Prescaler = 0x0, TIM3 counter clock = 36 MHz
TIM3 ARR Register = 999 => TIM3 Frequency = TIM3 counter clock/(ARR + 1)
TIM3 Frequency = 36 KHz.
TIM3 Channel1 duty cycle = (TIM3_CCR1/ TIM3_ARR)* 100 = 50%
TIM3 Channel2 duty cycle = (TIM3_CCR2/ TIM3_ARR)* 100 = 37.5%
TIM3 Channel3 duty cycle = (TIM3_CCR3/ TIM3_ARR)* 100 = 25%
TIM3 Channel4 duty cycle = (TIM3_CCR4/ TIM3_ARR)* 100 = 12.5%
----------------------------------------------------------------------- */
/* Time base configuration */
TIM_TimeBaseStructure.TIM_Period = 999; //当定时器从0计数到999,即为1000次,为一个定时周期
TIM_TimeBaseStructure.TIM_Prescaler = 0; //设置预分频:不预分频,即为36MHz
TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分频系数:不分频
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数模式
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
/* PWM1 Mode configuration: Channel1 */
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //配置为PWM模式1
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = CCR1_Val; //设置跳变值,当计数器计数到这个值时,电平发生跳变
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //当定时器计数值小于CCR1_Val时为高电平
TIM_OC1Init(TIM3, &TIM_OCInitStructure); //使能通道1
TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable);
/* PWM1 Mode configuration: Channel2 */
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = CCR2_Val; //设置通道2的电平跳变值,输出另外一个占空比的PWM
TIM_OC2Init(TIM3, &TIM_OCInitStructure); //使能通道2
TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);
/* PWM1 Mode configuration: Channel3 */
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = CCR3_Val; //设置通道3的电平跳变值,输出另外一个占空比的PWM
TIM_OC3Init(TIM3, &TIM_OCInitStructure); //使能通道3
TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Enable);
/* PWM1 Mode configuration: Channel4 */
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = CCR4_Val; //设置通道4的电平跳变值,输出另外一个占空比的PWM
TIM_OC4Init(TIM3, &TIM_OCInitStructure); //使能通道4
TIM_OC4PreloadConfig(TIM3, TIM_OCPreload_Enable);
TIM_ARRPreloadConfig(TIM3, ENABLE); // 使能TIM3重载寄存器ARR
/* TIM3 enable counter */
TIM_Cmd(TIM3, ENABLE); //使能定时器3
}
AT24C02的读写,相信大家都用过51单片机实现过,就是IIC总线操作。这里通过STM32来实现,个人理解没有很大的区别和难度,只要弄好AT24C02的驱动也就完事了(当然是废话了,外设操作都是搞驱动函数的啦)
附上自己的实验图片(参考野火的驱动就非常简单了):
例行附上AT24C02的配置代码,如下:
/*
* 函数名:I2C_GPIO_Config
* 描述 :I2C1 I/O配置
* 输入 :无
* 输出 :无
* 调用 :内部调用
*/
static void I2C_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* 使能与 I2C1 有关的时钟 */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE);
/* PB6-I2C1_SCL、PB7-I2C1_SDA*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD; // 开漏输出
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
/*
* 函数名:I2C_Configuration
* 描述 :I2C 工作模式配置
* 输入 :无
* 输出 :无
* 调用 :内部调用
*/
static void I2C_Mode_Configu(void)
{
I2C_InitTypeDef I2C_InitStructure;
/* I2C 配置 */
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
I2C_InitStructure.I2C_OwnAddress1 = I2C1_SLAVE_ADDRESS7;
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_InitStructure.I2C_ClockSpeed = I2C_Speed;
/* 使能 I2C1 */
I2C_Cmd(I2C1, ENABLE);
/* I2C1 初始化 */
I2C_Init(I2C1, &I2C_InitStructure);
/*允许1字节1应答模式*/
I2C_AcknowledgeConfig(I2C1, ENABLE);
}
/*
* 函数名:I2C_EE_Init
* 描述 :I2C 外设(EEPROM)初始化
* 输入 :无
* 输出 :无
* 调用 :外部调用
*/
void I2C_EE_Init(void)
{
I2C_GPIO_Config();
I2C_Mode_Configu();
/* 根据头文件i2c_ee.h中的定义来选择EEPROM要写入的地址 */
#ifdef EEPROM_Block0_ADDRESS
/* 选择 EEPROM Block0 来写入 */
EEPROM_ADDRESS = EEPROM_Block0_ADDRESS;
#endif
#ifdef EEPROM_Block1_ADDRESS
/* 选择 EEPROM Block1 来写入 */
EEPROM_ADDRESS = EEPROM_Block1_ADDRESS;
#endif
#ifdef EEPROM_Block2_ADDRESS
/* 选择 EEPROM Block2 来写入 */
EEPROM_ADDRESS = EEPROM_Block2_ADDRESS;
#endif
#ifdef EEPROM_Block3_ADDRESS
/* 选择 EEPROM Block3 来写入 */
EEPROM_ADDRESS = EEPROM_Block3_ADDRESS;
#endif
}
/*
* 函数名:I2C_EE_BufferWrite
* 描述 :将缓冲区中的数据写到I2C EEPROM中
* 输入 :-pBuffer 缓冲区指针
* -WriteAddr 接收数据的EEPROM的地址
* -NumByteToWrite 要写入EEPROM的字节数
* 输出 :无
* 返回 :无
* 调用 :外部调用
*/
void I2C_EE_BufferWrite(u8* pBuffer, u8 WriteAddr, u16 NumByteToWrite)
{
u8 NumOfPage = 0, NumOfSingle = 0, Addr = 0, count = 0;
Addr = WriteAddr % I2C_PageSize;
count = I2C_PageSize - Addr;
NumOfPage = NumByteToWrite / I2C_PageSize;
NumOfSingle = NumByteToWrite % I2C_PageSize;
/* If WriteAddr is I2C_PageSize aligned */
if(Addr == 0)
{
/* If NumByteToWrite < I2C_PageSize */
if(NumOfPage == 0)
{
I2C_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle);
I2C_EE_WaitEepromStandbyState();
}
/* If NumByteToWrite > I2C_PageSize */
else
{
while(NumOfPage--)
{
I2C_EE_PageWrite(pBuffer, WriteAddr, I2C_PageSize);
I2C_EE_WaitEepromStandbyState();
WriteAddr += I2C_PageSize;
pBuffer += I2C_PageSize;
}
if(NumOfSingle!=0)
{
I2C_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle);
I2C_EE_WaitEepromStandbyState();
}
}
}
/* If WriteAddr is not I2C_PageSize aligned */
else
{
/* If NumByteToWrite < I2C_PageSize */
if(NumOfPage== 0)
{
I2C_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle);
I2C_EE_WaitEepromStandbyState();
}
/* If NumByteToWrite > I2C_PageSize */
else
{
NumByteToWrite -= count;
NumOfPage = NumByteToWrite / I2C_PageSize;
NumOfSingle = NumByteToWrite % I2C_PageSize;
if(count != 0)
{
I2C_EE_PageWrite(pBuffer, WriteAddr, count);
I2C_EE_WaitEepromStandbyState();
WriteAddr += count;
pBuffer += count;
}
while(NumOfPage--)
{
I2C_EE_PageWrite(pBuffer, WriteAddr, I2C_PageSize);
I2C_EE_WaitEepromStandbyState();
WriteAddr += I2C_PageSize;
pBuffer += I2C_PageSize;
}
if(NumOfSingle != 0)
{
I2C_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle);
I2C_EE_WaitEepromStandbyState();
}
}
}
}
/*
* 函数名:I2C_EE_ByteWrite
* 描述 :写一个字节到I2C EEPROM中
* 输入 :-pBuffer 缓冲区指针
* -WriteAddr 接收数据的EEPROM的地址
* 输出 :无
* 返回 :无
* 调用 :外部调用
*/
void I2C_EE_ByteWrite(u8* pBuffer, u8 WriteAddr)
{
/* Send STRAT condition */
I2C_GenerateSTART(I2C1, ENABLE);
/* Test on EV5 and clear it */
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));
/* Send EEPROM address for write */
I2C_Send7bitAddress(I2C1, EEPROM_ADDRESS, I2C_Direction_Transmitter);
/* Test on EV6 and clear it */
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
/* Send the EEPROM's internal address to write to */
I2C_SendData(I2C1, WriteAddr);
/* Test on EV8 and clear it */
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
/* Send the byte to be written */
I2C_SendData(I2C1, *pBuffer);
/* Test on EV8 and clear it */
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
/* Send STOP condition */
I2C_GenerateSTOP(I2C1, ENABLE);
}
/*
* 函数名:I2C_EE_PageWrite
* 描述 :在EEPROM的一个写循环中可以写多个字节,但一次写入的字节数
* 不能超过EEPROM页的大小。AT24C02每页有8个字节。
* 输入 :-pBuffer 缓冲区指针
* -WriteAddr 接收数据的EEPROM的地址
* -NumByteToWrite 要写入EEPROM的字节数
* 输出 :无
* 返回 :无
* 调用 :外部调用
*/
void I2C_EE_PageWrite(u8* pBuffer, u8 WriteAddr, u8 NumByteToWrite)
{
while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY)); // Added by Najoua 27/08/2008
/* Send START condition */
I2C_GenerateSTART(I2C1, ENABLE);
/* Test on EV5 and clear it */
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));
/* Send EEPROM address for write */
I2C_Send7bitAddress(I2C1, EEPROM_ADDRESS, I2C_Direction_Transmitter);
/* Test on EV6 and clear it */
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
/* Send the EEPROM's internal address to write to */
I2C_SendData(I2C1, WriteAddr);
/* Test on EV8 and clear it */
while(! I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
/* While there is data to be written */
while(NumByteToWrite--)
{
/* Send the current byte */
I2C_SendData(I2C1, *pBuffer);
/* Point to the next byte to be written */
pBuffer++;
/* Test on EV8 and clear it */
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
}
/* Send STOP condition */
I2C_GenerateSTOP(I2C1, ENABLE);
}
/*
* 函数名:I2C_EE_BufferRead
* 描述 :从EEPROM里面读取一块数据。
* 输入 :-pBuffer 存放从EEPROM读取的数据的缓冲区指针。
* -WriteAddr 接收数据的EEPROM的地址。
* -NumByteToWrite 要从EEPROM读取的字节数。
* 输出 :无
* 返回 :无
* 调用 :外部调用
*/
void I2C_EE_BufferRead(u8* pBuffer, u8 ReadAddr, u16 NumByteToRead)
{
//*((u8 *)0x4001080c) |=0x80;
while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY)); // Added by Najoua 27/08/2008
/* Send START condition */
I2C_GenerateSTART(I2C1, ENABLE);
//*((u8 *)0x4001080c) &=~0x80;
/* Test on EV5 and clear it */
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));
/* Send EEPROM address for write */
I2C_Send7bitAddress(I2C1, EEPROM_ADDRESS, I2C_Direction_Transmitter);
/* Test on EV6 and clear it */
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
/* Clear EV6 by setting again the PE bit */
I2C_Cmd(I2C1, ENABLE);
/* Send the EEPROM's internal address to write to */
I2C_SendData(I2C1, ReadAddr);
/* Test on EV8 and clear it */
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
/* Send STRAT condition a second time */
I2C_GenerateSTART(I2C1, ENABLE);
/* Test on EV5 and clear it */
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));
/* Send EEPROM address for read */
I2C_Send7bitAddress(I2C1, EEPROM_ADDRESS, I2C_Direction_Receiver);
/* Test on EV6 and clear it */
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));
/* While there is data to be read */
while(NumByteToRead)
{
if(NumByteToRead == 1)
{
/* Disable Acknowledgement */
I2C_AcknowledgeConfig(I2C1, DISABLE);
/* Send STOP Condition */
I2C_GenerateSTOP(I2C1, ENABLE);
}
/* Test on EV7 and clear it */
if(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED))
{
/* Read a byte from the EEPROM */
*pBuffer = I2C_ReceiveData(I2C1);
/* Point to the next location where the byte read will be saved */
pBuffer++;
/* Decrement the read bytes counter */
NumByteToRead--;
}
}
/* Enable Acknowledgement to be ready for another reception */
I2C_AcknowledgeConfig(I2C1, ENABLE);
}
/*
* 函数名:I2C_EE_WaitEepromStandbyState
* 描述 :Wait for EEPROM Standby state
* 输入 :无
* 输出 :无
* 返回 :无
* 调用 :
*/
void I2C_EE_WaitEepromStandbyState(void)
{
vu16 SR1_Tmp = 0;
do
{
/* Send START condition */
I2C_GenerateSTART(I2C1, ENABLE);
/* Read I2C1 SR1 register */
SR1_Tmp = I2C_ReadRegister(I2C1, I2C_Register_SR1);
/* Send EEPROM address for write */
I2C_Send7bitAddress(I2C1, EEPROM_ADDRESS, I2C_Direction_Transmitter);
}while(!(I2C_ReadRegister(I2C1, I2C_Register_SR1) & 0x0002));
/* Clear AF flag */
I2C_ClearFlag(I2C1, I2C_FLAG_AF);
/* STOP condition */
I2C_GenerateSTOP(I2C1, ENABLE); // Added by Najoua 27/08/2008
}
TFT驱动起来了,目前没有做汉字的字库,所以还不能显示汉字。将图片贴出来啊,手机照的,TFT上的字符看不清,不过凭字形还是能够看出是我的EEPW ID的,哈哈。还有我的TFT是直立的插在开发板上的,所以感觉有点别扭。另外感谢hanshuyujifen2给我提供了LCD驱动代码啊,我一开始我认为自己的驱动是有问题的,后来发现原来是自己对TFT操作不熟练的原因,自己的驱动也是可以工作的。不过还是感谢hanshuyujifen2啊!
上图:
独立看门狗(IWDG)由专用的低速时钟(LSI)驱动,即使主时钟发生故障它也仍然有效。窗口看门狗由从APB1时钟分频后得到的时钟驱动,通过可配置的时间窗口来检测应用程序非正常的过迟或过早的操作。
IWDG最适合应用于那些需要看门狗作为一个在主程序之外,能够完全独立工作,并且对时间精度要求较低的场合。WWDG最适合那些要求看门狗在精确计时窗口起作用的应用程序。
在键寄存器(IWDG_KR)中写入0xCCCC,开始启用独立看门狗;此时计数器开始从其复位值0xFFF递减计数。当计数器计数到末尾0x000时,会产生一个复位信号(IWDG_RESET)。 无论何时,只要在键寄存器IWDG_KR中写入0xAAAA, IWDG_RLR中的值就会被重新加载到计数器,从而避免产生看门狗复位 。
这个独立看门狗的实验,用起来也是不难的,就是配置好看门狗之后,要按时喂狗,不然系统就会复位。这里参考原子的寄存器方式操作的,程序运行后则开启IWDG,并使得LED3常亮,在主循环里面不停的检测WK_UP按键是否按下,如果有按下,则喂狗,否则等待看门狗复位。看门狗复位可以看到LED3不停的闪烁。
由于实验较简单,而照相片不能较好的演示本实验,视频又挺麻烦的,所以就不上演示效果了。
现将独立看门狗的配置代码附上:
void IWDG_Init(u8 prer,u16 rlr)
{
IWDG->KR=0X5555;//使能对IWDG->PR和IWDG->RLR的写
IWDG->PR=prer; //设置分频系数
IWDG->RLR=rlr; //从加载寄存器 IWDG->RLR
IWDG->KR=0XAAAA;//reload
IWDG->KR=0XCCCC;//使能看门狗
}
//喂独立看门狗
void IWDG_Feed(void)
{
IWDG->KR=0XAAAA;//reload
}
回复
有奖活动 | |
---|---|
【有奖活动】分享技术经验,兑换京东卡 | |
话不多说,快进群! | |
请大声喊出:我要开发板! | |
【有奖活动】EEPW网站征稿正在进行时,欢迎踊跃投稿啦 | |
奖!发布技术笔记,技术评测贴换取您心仪的礼品 | |
打赏了!打赏了!打赏了! |
打赏帖 | |
---|---|
vscode+cmake搭建雅特力AT32L021开发环境被打赏30分 | |
【换取逻辑分析仪】自制底板并驱动ArduinoNanoRP2040ConnectLCD扩展板被打赏47分 | |
【分享评测,赢取加热台】RISC-V GCC 内嵌汇编使用被打赏38分 | |
【换取逻辑分析仪】-基于ADI单片机MAX78000的简易MP3音乐播放器被打赏48分 | |
我想要一部加热台+树莓派PICO驱动AHT10被打赏38分 | |
【换取逻辑分析仪】-硬件SPI驱动OLED屏幕被打赏36分 | |
换逻辑分析仪+上下拉与多路选择器被打赏29分 | |
Let'sdo第3期任务合集被打赏50分 | |
换逻辑分析仪+Verilog三态门被打赏27分 | |
换逻辑分析仪+Verilog多输出门被打赏24分 |