目录
一、系统时钟
1.初始化
ErrorStatus clk_return_status;
CLK_Source_TypeDef clk_source;
u32 u32_clk_freq;
void CLK_Config(void)
{
CLK_LSICmd(ENABLE); // 使能或禁用低速内部(LSI)时钟
#ifdef HSE
CLK_HSECmd(ENABLE); // 使能或禁用高速外部(HSE)时钟
while (SET != CLK_GetFlagStatus(CLK_FLAG_HSERDY)); // 等待HSE
clk_return_status = CLK_ClockSwitchConfig(CLK_SWITCHMODE_AUTO, CLK_SOURCE_HSE, DISABLE, CLK_CURRENTCLOCKSTATE_DISABLE);
#else
CLK_HSICmd(ENABLE); // 使能或禁用高速内部(HSI)时钟
CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV1); // 配置高速内部时钟(HSI)的预分频器
while (SET != CLK_GetFlagStatus(CLK_FLAG_HSIRDY)); // 等待HSI
#endif
clk_source = CLK_GetSYSCLKSource();
u32_clk_freq = CLK_GetClockFreq();
// printf("%u",u32_clk_freq);
CLK_SYSCLKConfig(CLK_PRESCALER_CPUDIV1); // 配置系统时钟(SYSCLK)的预分频器
}
2.HSE需要修改的地方
使用外部高速晶振时默认为无源晶振,有源晶振需要修改Option Bytes中的EXTCLK为1
修改外部高速晶振的频率,默认为16MHz,CLK_GetClockFreq();函数中需要用到
测试时外部晶振使用时还存在问题
二、定时器
1.TIM1
#define flicker_frequency 200 // ms
void TIM1_Config(void)
{
TIM1_TimeBaseInit(((CLK_GetClockFreq()/1000)-1), TIM1_COUNTERMODE_UP, flicker_frequency+1, 0);// 16M/(16M/1000-1+1)/200=200ms
TIM1_ClearFlag(TIM1_FLAG_UPDATE); // 清楚更新标志位
TIM1_ITConfig(TIM1_IT_UPDATE, ENABLE); // 使能更新中断
enableInterrupts(); // 开启中断
}
2.中断回调函数
/*main.h*/
typedef union
{
uint8_t all;
struct
{
uint8_t relay:2;
uint8_t led_R:2;
uint8_t led_G:2;
uint8_t led_Y:2;
}bits;
} slave_status_u;
/*stm8s_it.c*/
INTERRUPT_HANDLER(TIM1_UPD_OVF_TRG_BRK_IRQHandler, 11)
{
if (TIM1_GetITStatus(TIM1_IT_UPDATE) != RESET)
{
TIM1_ClearITPendingBit(TIM1_IT_UPDATE); // 清除中断标志
// printf("Timer 1 interrupt triggered\r\n");
if(status.bits.led_R == 3)
{
GPIO_WriteReverse(LED_GPIO_PORT,LED_GPIO_R);
}
if(status.bits.led_G == 3)
{
GPIO_WriteReverse(LED_GPIO_PORT,LED_GPIO_G);
}
if(status.bits.led_Y == 3)
{
GPIO_WriteReverse(LED_GPIO_PORT,LED_GPIO_Y);
}
}
}
3.TIM2
void TIM2_Config(void)
{
// CLK_PeripheralClockConfig(CLK_PERIPHERAL_TIMER2, ENABLE); //使能或禁用特定外设的时钟
TIM2_TimeBaseInit(TIM2_PRESCALER_1, (CLK_GetClockFreq()/1000)-1); // 1ms
TIM2_ClearFlag(TIM2_FLAG_UPDATE); // 清楚更新标志位
// TIM2_ITConfig(TIM2_IT_UPDATE, ENABLE); // 使能更新中断
enableInterrupts(); // 开启中断
}
4.Delay
void Delay (uint16_t Times)
{
TIM2_Cmd(ENABLE);
while(Times--)
{
while(RESET == TIM2_GetFlagStatus(TIM2_FLAG_UPDATE));
TIM2_ClearFlag(TIM2_FLAG_UPDATE);
}
TIM2_Cmd(DISABLE);
}
三、串口
1.标准库
void UART_Config(void)
{
/* Deinitializes the UART1 peripheral */
UART1_DeInit();
/* UART1 configuration -------------------------------------------------*/
/* UART1 configured as follow:
- BaudRate = 9600 baud 波特率
- Word Length = 8 Bits 数据位长度:8位
- One Stop Bit 停止位:1位
- No parity 奇偶校验:无奇偶校验
- Receive and transmit enabled 同步时钟:禁用
- UART1 Clock disabled 通信模式:收发模式
*/
/* Configure the UART1 */
UART1_Init((uint32_t)Baudrate, UART1_WORDLENGTH_8D, UART1_STOPBITS_1, UART1_PARITY_NO,
UART1_SYNCMODE_CLOCK_DISABLE, UART1_MODE_TXRX_ENABLE);
/* Enable UART1 IDLE interrupt*/
UART1_ITConfig(UART1_IT_RXNE_OR, ENABLE);//开启接收中断
UART1_ITConfig(UART1_IT_IDLE, ENABLE);//开启空闲中断
/* Enable general interrupts */
enableInterrupts();
}
2.寄存器库
void LL_UART_Config(void)
{
UART1->CR1=0x00;
UART1->CR2=0x00;
UART1->CR3=0x00;
UART1->BRR2 = 0x0B;//0x05;//0x0B; //8M、16MHz下115200波特率
UART1->BRR1 = 0x08;//0x04;//0x08; //8M、16MHz下115200波特率
UART1->CR2 |= (uint8_t)UART1_CR2_TEN;//允许发送
UART1->CR2 |= (uint8_t)UART1_CR2_REN;//允许接收
/* Enable UART1 IDLE interrupt*/
UART1->CR2 |= UART1_CR2_RIEN;
UART1->CR2 |= UART1_CR2_ILIEN;
/* Enable general interrupts */
enableInterrupts();
}
3.中断回调函数
INTERRUPT_HANDLER(UART1_RX_IRQHandler, 18)
{
if(UART1->SR & UART1_SR_RXNE)
{
if(UART1data.rxnum < 40)
UART1data.Data[UART1data.rxnum++] = UART1->DR;
else
UART1data.flag = 1;
}
else if(UART1->SR & UART1_SR_IDLE)
{
//清除空闲中断
UART1->SR;
UART1->DR;
UART1data.flag = 1;
}
}
4.printf
//printf
/**
* @brief Retargets the C library printf function to the UART.
* @param c Character to send
* @retval char Character sent
*/
PUTCHAR_PROTOTYPE
{
/* Write a character to the UART1 */
UART1_SendData8(c);
/* Loop until the end of transmission */
while (UART1_GetFlagStatus(UART1_FLAG_TXE) == RESET);
return (c);
}
/**
* @brief Retargets the C library scanf function to the USART.
* @param None
* @retval char Character to Read
*/
GETCHAR_PROTOTYPE
{
#ifdef _COSMIC_
char c = 0;
#else
int c = 0;
#endif
/* Loop until the Read data register flag is SET */
while (UART1_GetFlagStatus(UART1_FLAG_RXNE) == RESET);
c = UART1_ReceiveData8();
return (c);
}
5.普通发送函数
void UART1_SendString(const char *str)
{
// 遍历字符串,直到遇到空字符 '\0'(字符串结束标志)
while (*str != '\0')
{
UART1_SendData8((uint8_t)*str);
while(!UART1_GetFlagStatus(UART1_FLAG_TC));
str++;
}
}
四、GPIO
1.初始化
标准库
void GPIO_Config(void)
{
// GPIO_Init(GPIOB, GPIO_PIN_5, GPIO_MODE_OUT_PP_LOW_FAST); // 板载灯,与IIC冲突
// GPIO_Init(ARM_IO1_PORT, ARM_IO1_PINS, GPIO_MODE_IN_FL_NO_IT); // 暂未使用
// GPIO_Init(ARM_IO2_PORT, ARM_IO2_PINS, GPIO_MODE_IN_FL_NO_IT); // 暂未使用
// GPIO_Init(GPIOA, GPIO_PIN_2, GPIO_MODE_OUT_PP_LOW_FAST); // 空闲引脚
GPIO_Init(LED_GPIO_PORT, (GPIO_Pin_TypeDef)LED_GPIO_PINS, GPIO_MODE_OUT_PP_HIGH_FAST);
GPIO_Init(RELAY_GPIO_PORT, (GPIO_Pin_TypeDef)RELAY_GPIO_PINS, GPIO_MODE_OUT_PP_LOW_FAST);
GPIO_Init(REL_GPIO_PORT, REL_GPIO_2, GPIO_MODE_IN_PU_NO_IT);
}
寄存器库
void LL_GPIO_Config(void)
{
GPIOC->DDR = 1<<4|1<<5|1<<6|0<<7;
GPIOC->CR1 = 1<<4|1<<5|1<<6|1<<7;
GPIOC->CR2 = 1<<4|1<<5|1<<6|0<<7;
GPIOC->ODR = 0<<4|0<<5|0<<6|0<<7;
GPIOD->DDR = 1<<2|1<<3|1<<4;
GPIOD->CR1 = 1<<2|1<<3|1<<4;
GPIOD->CR2 = 1<<2|1<<3|1<<4;
GPIOD->ODR = 1<<2|1<<3|1<<4;
}
2. 中断
标准库
GPIO_Init(ARM_IO1_PORT, ARM_IO1_PINS, GPIO_MODE_IN_FL_IT);
EXTI_SetExtIntSensitivity(EXTI_PORT_GPIOA,EXTI_SENSITIVITY_RISE_FALL);
enableInterrupts();
寄存器库
GPIOA->DDR = 0<<3;
GPIOA->CR1 = 0<<3;
GPIOA->CR2 = 1<<3;
GPIOA->ODR = 0<<3;
EXTI->CR1 &= (uint8_t)(~EXTI_CR1_PAIS);
EXTI->CR1 |= (uint8_t)(EXTI_SENSITIVITY_RISE_FALL);
中断回调函数
INTERRUPT_HANDLER(EXTI_PORTA_IRQHandler, 3)
{
printf("EXTI");
if ((GPIO_ReadInputData(ARM_IO1_PORT) & ARM_IO1_PINS) == ARM_IO1_PINS)
{
GPIO_WriteHigh(ARM_IO2_PORT,ARM_IO2_PINS);
printf("high\r\n");
}
else if ((GPIO_ReadInputData(ARM_IO1_PORT) & ARM_IO1_PINS) == 0x00)
{
GPIO_WriteLow(ARM_IO2_PORT,ARM_IO2_PINS);
printf("LOW\r\n");
}
}
五、I2C
1.标准库
void IIC_Config(void)
{
// CLK_PeripheralClockConfig(CLK_PERIPHERAL_I2C, ENABLE); //使能或禁用特定外设的时钟
// I2C_DeInit();
I2C_Init(SLAVE_CLOCK, SLAVE_ADDRESS, I2C_DUTYCYCLE_2, I2C_ACK_CURR, I2C_ADDMODE_7BIT, CLK_GetClockFreq()/1000000);
I2C_ITConfig((I2C_IT_TypeDef)(I2C_IT_ERR | I2C_IT_EVT), ENABLE);
enableInterrupts();
// I2C_Cmd(ENABLE);
}
2.寄存器库
void LL_IIC_Config(void)
{
//IIC
/* Write new frequency bits */
I2C->FREQR = 16;
/* Write CCR with new calculated value */
I2C->CCRL = (uint8_t)((16*1000000)/(SLAVE_CLOCK*3));
I2C->CCRH = (uint8_t)((uint8_t)((uint8_t)(((16*1000000)/(SLAVE_CLOCK*3)) >> 8) & I2C_CCRH_CCR) | I2C_CCRH_FS);
/* Enable I2C */
I2C->CR1 |= 0x01;
/* Enable the acknowledgement */
I2C->CR2 |= I2C_CR2_ACK;
/* Configure (N)ACK on current byte */
I2C->CR2 &= (uint8_t)(~I2C_CR2_POS);
/*--------------------------- I2C OAR Configuration ------------------------*/
I2C->OARL = (uint8_t)(SLAVE_ADDRESS);
I2C->OARH = (uint8_t)((uint8_t)(I2C_ADDMODE_7BIT | I2C_OARH_ADDCONF) | (uint8_t)((SLAVE_ADDRESS & (uint16_t)0x0300) >> (uint8_t)7));
// 启用IIC中断
I2C->ITR |= (uint8_t)(I2C_IT_ERR | I2C_IT_EVT | I2C_IT_BUF);
enableInterrupts();
}
3.中断回调函数
/*stm8s_it.h*/
typedef struct {
uint8_t Command; // 命令
uint8_t SubCmd; // 子命令
uint8_t SubData; // 子命令数据
} MyBuffer;
typedef enum
{
iic_start = 0,
iic_sent,
iic_received ,
iic_addr,
iic_stop,
iic_sending,
iic_af,
}iic_status_e;
extern MyBuffer protocol;
/*stm8s_it.c*/
#define Protocol_return 0x80
#define TXE_flag (1 << 7)
#define RXNE_flag (1 << 6)
#define ADDR_flag (1 << 1)
#define AF_flag (1 << 2)
#define STOPF_flag (1 << 4)
#define TRA_mode (1 << 2)
uint8_t Slave_Buffer_Rx[10];
uint8_t TransmitData[10];
uint8_t Tx_Idx = 0, Rx_Idx = 0;
MyBuffer protocol;
iic_status_e state = iic_start;
INTERRUPT_HANDLER(I2C_IRQHandler, 19)
{
uint8_t temp=0;
// printf("LastEvent=%d\r\n",I2C_GetLastEvent());
// printf("ReceiveData=%d\r\n",I2C_ReceiveData());
if(I2C->SR1 & TXE_flag) // 发送完成
{
state = iic_sent;
}
else if(I2C-> SR1 & RXNE_flag) // 接收非空
{
state = iic_received;
}
else if(I2C->SR1 & ADDR_flag) // 地址匹配
{
if(I2C->SR3 & TRA_mode) // 发送数据
{
state = iic_sending;
}
else // 接收数据
{
state = iic_addr;
temp = I2C->SR3;
}
}
else if(I2C->SR2 & AF_flag) // 应答失败(发送完成)
{
I2C->SR2 &= ~AF_flag;
state = iic_af;
}
if(I2C->SR1 &STOPF_flag) // 检测到停止位
{
if(I2C-> SR1 & RXNE_flag)
{
state = iic_received; // 接收最后一个数据时RXNE和STOPF同时出现
}
else
{
state = iic_stop; // 接收完成
temp = I2C->SR1;
temp = I2C->CR2;
I2C->CR2 = temp;
}
}
switch(state)
{
case iic_received:
Slave_Buffer_Rx[Rx_Idx++] = I2C_ReceiveData();
break;
case iic_stop:
if(Rx_Idx != 3)
break;
// memcpy((uint8_t *)&protocol, Slave_Buffer_Rx, 3);
protocol.Command = Slave_Buffer_Rx[0];
protocol.SubCmd = Slave_Buffer_Rx[1];
protocol.SubData = Slave_Buffer_Rx[2];
if(DataHandle(&protocol) != HAL_OK)
{
protocol.SubData = 0xFF;
#ifdef debug
printf("IIC receive data error!\r\n");
#endif
}
protocol.Command |=Protocol_return;
Rx_Idx = 0;
break;
case iic_sending:
Tx_Idx = 0;
// memcpy(TransmitData, (uint8_t*)&protocol, 3);
TransmitData[0] = protocol.Command;
TransmitData[1] = protocol.SubCmd ;
TransmitData[2] = protocol.SubData;
I2C_SendData(TransmitData[Tx_Idx++]);
break;
case iic_sent:
I2C_SendData(TransmitData[Tx_Idx++]);
break;
case iic_af:
break;
}
}
六、EEPROM
1.寄存器库
void LL_EEP_Init(void)
{
FLASH->CR1 = 0x00;
FLASH->CR2 = 0x00;
FLASH->NCR2 = 0xff;
FLASH->DUKR = MASS_KEY1;
FLASH->DUKR = MASS_KEY2;
while(!FLASH_IAPSR_DUL); //等待写保护解锁
}
2.写函数
void eep_write(uint16_t addr,uint8_t dat) //不同芯片,EEPROM容量不同-小容量640字节
{
*((uint8_t*)(addr + EEP_BASE)) = dat;
while(!FLASH_IAPSR_EOP); //等待写完成
}
七、IWDG
寄存器库
void LL_WDT_Init(void)
{
IWDG->KR = 0xCC; //启动看门狗
IWDG->KR = 0x55; //解除写保护
IWDG->PR = 0x06; //256分频,最高1.02秒
IWDG->RLR = 125; //500ms
IWDG->KR = 0xAA; //写保护
}