新学期新气象,新学期我们要学32了,之前虽然学了一点点,但是学的都不是很系统,这里终于能系统的学习一下32了,从原理角度进行一下学习。
嵌入式就是在单片机上跑操作系统
STM32芯片内部
这是STM32的命名规则
时钟最高72M
PIN to PIN兼容是指两款芯片的引脚数目一样,功能一样,大小也一样
通过修改BOOT0和BOOT1的方式来修改32的启动方式,利用跳线帽改这个
将2,4等引脚短接来修改其启动方式
void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET);
/*Configure GPIO pin : PA8 */
GPIO_InitStruct.Pin = GPIO_PIN_8;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
下面是标准库的配置
void LED_Init(void)
{
GPIO_InitTypeDef GPIO_InitTypeStrucre;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitTypeStrucre.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitTypeStrucre.GPIO_Pin=GPIO_Pin_8 ;
GPIO_InitTypeStrucre.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitTypeStrucre);
GPIO_SetBits(GPIOA,GPIO_Pin_8 );
}
HAL_Delay(1)实际延时时间多于1ms一点
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
HAL_Delay(300);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET);
HAL_Delay(300);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_SET);
什么是看门狗?
是一个定时器,将里面的数值加到一定数值之后,会被复位
所以在程序中每隔多少秒要把看门狗复位
看门狗主要用于无人看管的程序,防止程序跑飞了
GPIO:General Purpose Input Output,通用输入输出
输出三种:1.推挽2.开漏3.关闭
KEY0采用上拉模式和输入模式
我一般习惯把名字起的和原理图一模一样,这样代码读起来方便
while (1)
{
if(HAL_GPIO_ReadPin(KEY0_GPIO_Port, KEY0_Pin)==GPIO_PIN_RESET)
{
HAL_Delay(10);
if(HAL_GPIO_ReadPin(KEY0_GPIO_Port, KEY0_Pin)==GPIO_PIN_RESET)
{
HAL_GPIO_TogglePin(LED0_GPIO_Port,LED0_Pin);
while(HAL_GPIO_ReadPin(KEY0_GPIO_Port, KEY0_Pin)==GPIO_PIN_RESET);
}
}
/* USER CODE END WHILE */
}
下载后要先按一下Reset才能成功执行
让LED0闪烁,LED1灭
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
HAL_Delay(300);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET);
HAL_Delay(300);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
}
如果按下按键,则LED1亮,表示进入外部中断
__weak void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(GPIO_Pin);
/* NOTE: This function Should not be modified, when the callback is needed,
the HAL_GPIO_EXTI_Callback could be implemented in the user file
*/
if(GPIO_Pin==GPIO_PIN_1)
{
if(HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_1)==0)
{
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);
}
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_1);
}
}
第四节课系统学习了外部中断
在CUBE中都设置为GPIO_EXTI模式
因为KEY0接地,我们配置成上拉模式
同理,配置WKUP
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
delay_ms(500);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
delay_ms(500);
}
/* USER CODE END 3 */
delay_ms
//毫秒延时
void delay_ms(uint16_t nms)
{
uint32_t temp;
SysTick->LOAD = 9000*nms;
SysTick->VAL=0X00;//清空计数器
SysTick->CTRL=0X01;//使能,减到零是无动作,采用外部时钟源
do
{
temp=SysTick->CTRL;//读取当前倒计数值
}while((temp&0x01)&&(!(temp&(1<<16))));//等待时间到达
SysTick->CTRL=0x00; //关闭计数器
SysTick->VAL =0X00; //清空计数器
}
__weak void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(GPIO_Pin);
/* NOTE: This function Should not be modified, when the callback is needed,
the HAL_GPIO_EXTI_Callback could be implemented in the user file
*/
if(GPIO_Pin==GPIO_PIN_1)
{
if(HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_1)==0)
{
for(int i=0;i<20;i++)
{
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_8,GPIO_PIN_RESET);
delay_ms(200);
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_8,GPIO_PIN_SET);
delay_ms(200);
}
}
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_1);
}
if(GPIO_Pin==GPIO_PIN_0)
{
if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)==0)
{
for(int i=0;i<20;i++)
{
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_8,GPIO_PIN_SET);
delay_ms(200);
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_8,GPIO_PIN_RESET);
delay_ms(200);
}
}
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_0);
}
}
在这个作业中不要将按键设置成浮空,浮空状态会有点问题,要根据引脚设置成需要的状态
周期表
p n u m 1 K M G T
更新事件Update event(UE)
可以把CNT清零
定时器时间t=1/Tout
如果使能影子寄存器,影子寄存器会在更新事件发生时,将内部数值更新到ARR
ARR是计算时间间隔所以要加1
因为PSC不能为0,所以要加上1
(4999+1)*(7199+1)=36000000
72000000/36000000=2
1/2=0.5s=500ms
main.c
/* USER CODE BEGIN PV */
static int i=0;
/* USER CODE END PV */
/* USER CODE BEGIN 2 */
HAL_TIM_Base_Start_IT(&htim2);
HAL_TIM_Base_Start_IT(&htim3);
/* USER CODE END 2 */
在stm32f10x_hal_tim.c中找到中断回调函数,在main.c中重定义
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim==&htim2)
{
HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_8);//对GPIO口的电平进行反转(低-高,高—低)
}
if(htim==&htim3)
{
if(++i>=700)
{
i=0;
HAL_GPIO_TogglePin(GPIOD,GPIO_PIN_2);//对GPIO口的电平进行反转(低-高,高—低)
}
}
/* USER CODE BEGIN 1 */
int i=500;
/* USER CODE END 1 */
/* USER CODE BEGIN 2 */
HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1); // 使能PWM输出
/* USER CODE END 2 */
/* USER CODE BEGIN 3 */
if(HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_1)==GPIO_PIN_RESET)
{
HAL_Delay(10);
if(HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_1)==GPIO_PIN_RESET)
{
i=i+1;
htim1.Instance->CCR1 = i;
HAL_Delay(1);
while(HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_1)==GPIO_PIN_RESET);
}
}
if(HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_13)==GPIO_PIN_RESET)
{
HAL_Delay(10);
if(HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_13)==GPIO_PIN_RESET)
{
i=i-1;
htim1.Instance->CCR1 = i;
HAL_Delay(1);
while(HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_13)==GPIO_PIN_RESET);
}
}
}
/* USER CODE END 3 */
/**
* 函数功能: 重定向c库函数printf到DEBUG_USARTx
* 输入参数: 无
* 返 回 值: 无
* 说 明:无
*/
int fputc(int ch, FILE *f)
{
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff);
return ch;
}
/**
* 函数功能: 重定向c库函数getchar,scanf到DEBUG_USARTx
* 输入参数: 无
* 返 回 值: 无
* 说 明:无
*/
int fgetc(FILE *f)
{
uint8_t ch = 0;
HAL_UART_Receive(&huart1, &ch, 1, 0xffff);
return ch;
}
定义了一个字符串
/* USER CODE BEGIN 1 */
char str[10];
/* USER CODE END 1 */
因为scanf在单片机中并不是阻塞式接收,所以我们要将其改为阻塞式的
/* USER CODE BEGIN 3 */
printf("测试发送\n");
HAL_Delay(100);
str[0]=0;
while(str[0] == 0)
{
scanf("%s",str);
}//使其变成手动的阻塞式接收
HAL_Delay(1000);
printf("output:%s\n",str);