

62楼
为了能用示波器看到系统时钟,决定将系统时钟输出到MCO引脚上去。
弄了一晚上,看见波形了。
首先建立空的工程,将下面三行代码注释掉:
;IMPORT SystemInit ;删除SystemInit自己写RCC初始化函数
;LDR R0, =SystemInit
;BLX R0
下面是设置函数,使用HSI作为系统时钟,不实用PLL,直接将HSI输出到MCO引脚:
void My_RccInitMCOHSI(void)
{
uint8_t temp;
My_Rcc_DeInit();
RCC->CR |= 1<<0; //复位HSION 开启内部时钟;其实内部时钟不用管的,开机自动使用内部时钟。
while(!(RCC->CR>>1)); //检查HSI是否就绪
RCC->CFGR &= (~0x03); //清零CFGR的0、1位 HSI作为系统时钟
while(temp!=0x00) //读取CFGR的2、3为,判断是否是HSI作为系统时钟设置
{
temp=RCC->CFGR>>2;
temp&=0x03;
}
//此时HSI已经成为系统时钟
//HSI时钟就绪后,直接输出到MCO(PA8)
RCC->APB2ENR |= 1<<2; //使能PA时钟
RCC->APB2ENR|=1<<5; //使能PORTD时钟
GPIOA->CRH&=0XFFFFFFF0;
GPIOA->CRH|=0X0000000B;//PA8 推挽输出(MCO)
// //设置MCO输出内部HSI时钟
RCC->CFGR |= 5<<24; //MCO输出HSI时钟
//RCC->CFGR |= 4<<24; MCO输出系统时钟SYSCLK
//此时就可以在PA8即MCO引脚看见输出波形了 对比下,两者是一样的。
}
下边是示波器出来的图:

示波器探针位置,插到PA8上去。已经印出来了,没焊,探针刚好插进去
弄了一晚上,看见波形了。
首先建立空的工程,将下面三行代码注释掉:
;IMPORT SystemInit ;删除SystemInit自己写RCC初始化函数
;LDR R0, =SystemInit
;BLX R0
下面是设置函数,使用HSI作为系统时钟,不实用PLL,直接将HSI输出到MCO引脚:
void My_RccInitMCOHSI(void)
{
uint8_t temp;
My_Rcc_DeInit();
RCC->CR |= 1<<0; //复位HSION 开启内部时钟;其实内部时钟不用管的,开机自动使用内部时钟。
while(!(RCC->CR>>1)); //检查HSI是否就绪
RCC->CFGR &= (~0x03); //清零CFGR的0、1位 HSI作为系统时钟
while(temp!=0x00) //读取CFGR的2、3为,判断是否是HSI作为系统时钟设置
{
temp=RCC->CFGR>>2;
temp&=0x03;
}
//此时HSI已经成为系统时钟
//HSI时钟就绪后,直接输出到MCO(PA8)
RCC->APB2ENR |= 1<<2; //使能PA时钟
RCC->APB2ENR|=1<<5; //使能PORTD时钟
GPIOA->CRH&=0XFFFFFFF0;
GPIOA->CRH|=0X0000000B;//PA8 推挽输出(MCO)
// //设置MCO输出内部HSI时钟
RCC->CFGR |= 5<<24; //MCO输出HSI时钟
//RCC->CFGR |= 4<<24; MCO输出系统时钟SYSCLK
//此时就可以在PA8即MCO引脚看见输出波形了 对比下,两者是一样的。
}
下边是示波器出来的图:

示波器探针位置,插到PA8上去。已经印出来了,没焊,探针刚好插进去


63楼
HSE直接作为SYSCLK。与HSI相似
设置方法如下,代码中有注释:
void My_RccInitMCOHSE(void)
{
uint8_t temp;
My_Rcc_DeInit();
RCC->CR |= 1<<16; //开启HSEON 开启外部时钟。
while(!(RCC->CR>>17)); //等待HSE就绪
//选择HSE作为系统时钟
RCC->CFGR |= 0x01;
while(temp!=0x01) //读取CFGR的2、3为,判断是否是HSE作为系统时钟设置
{
temp=RCC->CFGR>>2;
temp&=0x03;
}
//此时HSE已经成为系统时钟
//HSE时钟就绪后,直接输出到MCO(PA8)
RCC->APB2ENR |= 1<<2; //使能PA时钟
GPIOA->CRH&=0XFFFFFFF0;
GPIOA->CRH|=0X0000000B;//PA8 推挽输出(MCO)
//设置MCO输出内部HSE时钟
RCC->CFGR |= 0x06<<24; //MCO输出HSE时钟
//RCC->CFGR |= 4<<24; MCO输出系统时钟SYSCLK
//此时就可以在PA8即MCO引脚看见输出波形了 对比下,两者是一样的。
}
按照惯例,最后是图片。我使用的是12M的晶振。

64楼
PLL部分只放代码和图,刚才写了半天,提示2分钟只能提交5次信息,然后就没了。
郁闷的不想再写了
void My_RccInitMCOPLL(uint8_t PLL)
{
uint8_t temp;
My_Rcc_DeInit();
RCC->CR |= 1<<16; //开启HSEON 开启外部时钟。
while(!(RCC->CR>>17)); //等待HSE就绪
//选择HSE作为系统时钟
//RCC->CFGR |= 0x01;
//设置PLL倍频数
PLL -= 2; //根据PLL倍频系数与RCC->CFGR的18到21位得出(PLLMUL)
RCC->CFGR |= PLL<<18;
RCC->CFGR |= 1<<16; //HSE作为PLL时钟源
RCC->CR |= 1<<24;
while(!(RCC->CR>>25));//等待PLL锁定
//选择PLL输出作为系统时钟源
RCC->CFGR |= 0x02;
while(temp!=0x02) //读取CFGR的2、3为,判断是否是HSE作为系统时钟设置
{
temp=RCC->CFGR>>2;
temp&=0x03;
}
//此时HSE已经成为系统时钟
//HSE时钟就绪后,直接输出到MCO(PA8)
RCC->APB2ENR |= 1<<2; //使能PA时钟
GPIOA->CRH&=0XFFFFFFF0;
GPIOA->CRH|=0X0000000B;//PA8 推挽输出(MCO)
//设置MCO输出内部HSE时钟
RCC->CFGR |= 0x07<<24; //MCO输出HSE时钟
//RCC->CFGR |= 4<<24; // MCO输出系统时钟SYSCLK
//此时就可以在PA8即MCO引脚看见输出波形了 对比下,两者是一样的。
}




郁闷的不想再写了
void My_RccInitMCOPLL(uint8_t PLL)
{
uint8_t temp;
My_Rcc_DeInit();
RCC->CR |= 1<<16; //开启HSEON 开启外部时钟。
while(!(RCC->CR>>17)); //等待HSE就绪
//选择HSE作为系统时钟
//RCC->CFGR |= 0x01;
//设置PLL倍频数
PLL -= 2; //根据PLL倍频系数与RCC->CFGR的18到21位得出(PLLMUL)
RCC->CFGR |= PLL<<18;
RCC->CFGR |= 1<<16; //HSE作为PLL时钟源
RCC->CR |= 1<<24;
while(!(RCC->CR>>25));//等待PLL锁定
//选择PLL输出作为系统时钟源
RCC->CFGR |= 0x02;
while(temp!=0x02) //读取CFGR的2、3为,判断是否是HSE作为系统时钟设置
{
temp=RCC->CFGR>>2;
temp&=0x03;
}
//此时HSE已经成为系统时钟
//HSE时钟就绪后,直接输出到MCO(PA8)
RCC->APB2ENR |= 1<<2; //使能PA时钟
GPIOA->CRH&=0XFFFFFFF0;
GPIOA->CRH|=0X0000000B;//PA8 推挽输出(MCO)
//设置MCO输出内部HSE时钟
RCC->CFGR |= 0x07<<24; //MCO输出HSE时钟
//RCC->CFGR |= 4<<24; // MCO输出系统时钟SYSCLK
//此时就可以在PA8即MCO引脚看见输出波形了 对比下,两者是一样的。
}





65楼
串口读取主片ID
电子签名存放在闪存存储器模块的系统存储区域,可以通过JTAG/SWD或者CPU读取。它所包
含的芯片识别信息在出厂时编写,用户固件或者外部设备可以读取电子签名
电子签名包括两个寄存器:1、存储器容量寄存器 2、产品唯一身份标识寄存器(96位)
闪存容量寄存器的基址是:0x1FFF F7E0
产品唯一身份标识寄存器(96位) 的基地址:0x1FFF F7E8
因此只要读出这四个地址内的数据,就能得到芯片ID和容量。
下面是获取芯片ID的函数,读出ID放到一个数组中:
//读ID
void GetID(void)
{
ChipID[0] = *(__IO u32 *)(0X1FFFF7F0);
ChipID[1] = *(__IO u32 *)(0X1FFFF7EC);
ChipID[2] = *(__IO u32 *)(0X1FFFF7E8);
}
//读容量
uint_16 GetChipAmount(void)
{
return *(__IO u16 *)(0X1FFFF7E0);
}
最后串口显示:
printf("\r\n芯片ID: %X %X %X\r\n",ChipID[0],ChipID[1],ChipID[2]);
printf("\r\n芯片flash大小: %dK \r\n", GetChipAmount());
当然,例行性的东西是不能忘的:
电子签名存放在闪存存储器模块的系统存储区域,可以通过JTAG/SWD或者CPU读取。它所包
含的芯片识别信息在出厂时编写,用户固件或者外部设备可以读取电子签名
电子签名包括两个寄存器:1、存储器容量寄存器 2、产品唯一身份标识寄存器(96位)
闪存容量寄存器的基址是:0x1FFF F7E0
产品唯一身份标识寄存器(96位) 的基地址:0x1FFF F7E8
因此只要读出这四个地址内的数据,就能得到芯片ID和容量。
下面是获取芯片ID的函数,读出ID放到一个数组中:
//读ID
void GetID(void)
{
ChipID[0] = *(__IO u32 *)(0X1FFFF7F0);
ChipID[1] = *(__IO u32 *)(0X1FFFF7EC);
ChipID[2] = *(__IO u32 *)(0X1FFFF7E8);
}
//读容量
uint_16 GetChipAmount(void)
{
return *(__IO u16 *)(0X1FFFF7E0);
}
最后串口显示:
printf("\r\n芯片ID: %X %X %X\r\n",ChipID[0],ChipID[1],ChipID[2]);
printf("\r\n芯片flash大小: %dK \r\n", GetChipAmount());
当然,例行性的东西是不能忘的:

66楼
时钟初始化遇见的问题。
在系统初始化好之后,即SystemInit函数执行完毕之后,系统时钟应该是72MHz的。
之后初始化SysTick作为延时用。
原计划每隔1ms进行一次LED反转。可示波器看了之后,发现输出频率是55.8Hz左右
单步执行SystemInit,测出来的LED反转频率确是精准的500赫兹。
为什么?
SetSysClockTo72();函数中有这么一段:
do
{
HSEStatus = RCC->CR & RCC_CR_HSERDY;
// StartUpCounter++; //删除此行,强制使用外部晶振。
} while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
HSE_STARTUP_TIMEOUT是重试的次数。
次数超过这个之后,就不使用PLL作为系统时钟了。
也就是说,系统还是使用了内部8MHZ的晶振作为系统时钟源。
如果72MHz时候产生500Hz的反转频率,那么8MHz产生的反转频率应该是这样的:
f = 500×8/72 = 55.5555。。。。
跟实际的频率差不多。
估计是我的晶振初始化太慢了,500多个时钟周期启动不起来。于是我删掉了这行
// StartUpCounter++; //删除此行,强制使用外部晶振。
如果外部晶振初始化不成功,就给我死这里吧!
在系统初始化好之后,即SystemInit函数执行完毕之后,系统时钟应该是72MHz的。
之后初始化SysTick作为延时用。
原计划每隔1ms进行一次LED反转。可示波器看了之后,发现输出频率是55.8Hz左右
单步执行SystemInit,测出来的LED反转频率确是精准的500赫兹。
为什么?
SetSysClockTo72();函数中有这么一段:
do
{
HSEStatus = RCC->CR & RCC_CR_HSERDY;
// StartUpCounter++; //删除此行,强制使用外部晶振。
} while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
HSE_STARTUP_TIMEOUT是重试的次数。
次数超过这个之后,就不使用PLL作为系统时钟了。
也就是说,系统还是使用了内部8MHZ的晶振作为系统时钟源。
如果72MHz时候产生500Hz的反转频率,那么8MHz产生的反转频率应该是这样的:
f = 500×8/72 = 55.5555。。。。
跟实际的频率差不多。
估计是我的晶振初始化太慢了,500多个时钟周期启动不起来。于是我删掉了这行
// StartUpCounter++; //删除此行,强制使用外部晶振。
如果外部晶振初始化不成功,就给我死这里吧!

67楼
参考ST库中的写法写出来的。
不是很规范但板子能用
单总线,时间要求比较严格。在处理好RCC之后,弄单总线就不是很难了。参考原子的东西,我懒。。
主函数中调用方法,每秒更新一次温度:
while(STM_EEPW_DS18B201Init(DS18B201))//初始化DS18B20,兼检测18B20
{
STM_EEPW_LEDToggle(LED1);//DS0闪烁
delay_ms(50);
}
while(1)
{
temperature = DS18B201_Get_Temp(DS18B201);
printf("当前温度是:%d.%d\r\n",temperature/10,temperature%10);
delay_ms(1000);
}
显示效果:
我屋子里边温度 是20.8度,话说早上上班的时候,还看见路边水池结冰了呢,晚上就而是多度了。

不是很规范但板子能用
单总线,时间要求比较严格。在处理好RCC之后,弄单总线就不是很难了。参考原子的东西,我懒。。
主函数中调用方法,每秒更新一次温度:
while(STM_EEPW_DS18B201Init(DS18B201))//初始化DS18B20,兼检测18B20
{
STM_EEPW_LEDToggle(LED1);//DS0闪烁
delay_ms(50);
}
while(1)
{
temperature = DS18B201_Get_Temp(DS18B201);
printf("当前温度是:%d.%d\r\n",temperature/10,temperature%10);
delay_ms(1000);
}
显示效果:
我屋子里边温度 是20.8度,话说早上上班的时候,还看见路边水池结冰了呢,晚上就而是多度了。


68楼
串口定时器1(TIM1)生成占空比为50% 的方波
串口发送1产生1.5K方波 2->2K 3->3K 4->4K 发送其他产生1M方波
有视频,问老王要了几次,都不给验证码只好传优库了 正在审核。
操作麻烦,不好贴图片,代码贴出:
//使用TIM进行PWM输出方波
#include "stm32f10x.h"
#include "TIM.h"
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
uint16_t TimerPeriod = 0;
uint16_t Channel1Pulse = 0, Channel2Pulse = 0, Channel3Pulse = 0, Channel4Pulse = 0;
//时钟初始化
void PWM_RCCConfiguration()
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1 | RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOE|
RCC_APB2Periph_GPIOB |RCC_APB2Periph_AFIO, ENABLE);
}
//GPIO配置函数
void PWM_GPIOConfiguration()
{
GPIO_InitTypeDef GPIO_InitStructure;
/* GPIOA Configuration: Channel 1, 2 and 3 as alternate function push-pull */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_11;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* GPIOB Configuration: Channel 1N, 2N and 3N as alternate function push-pull */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
//演示函数 开启了串口对应引脚PA9PA10的AFIO时钟,就不能和串口1同时使用了。
void PWM_Disp(void)
{
PWM_RCCConfiguration();
PWM_GPIOConfiguration();
if(TimerPeriod == 0)
TimerPeriod = (SystemCoreClock / 17570 ) - 1;
Channel1Pulse = (uint16_t) (((uint32_t) 5 * (TimerPeriod - 1)) / 10);
Channel2Pulse = (uint16_t) (((uint32_t) 375 * (TimerPeriod - 1)) / 1000);
Channel3Pulse = (uint16_t) (((uint32_t) 25 * (TimerPeriod - 1)) / 100);
Channel4Pulse = (uint16_t) (((uint32_t) 125 * (TimerPeriod- 1)) / 1000);
//系统时钟预分频数 0表示不分配 1表示2分频 2表示3分配。。。。。。
TIM_TimeBaseStructure.TIM_Prescaler = 0;
//计数器模式为向上计数
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
//PWM周期
TIM_TimeBaseStructure.TIM_Period = TimerPeriod;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
//收到更新数据,用最快速度更新
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
/* Channel 1, 2,3 and 4 Configuration in PWM mode */
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;
TIM_OCInitStructure.TIM_Pulse = Channel1Pulse;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;
TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Reset;
TIM_OC1Init(TIM1, &TIM_OCInitStructure);
TIM_OCInitStructure.TIM_Pulse = Channel4Pulse;
TIM_OC4Init(TIM1, &TIM_OCInitStructure);
/* TIM1 counter enable */
TIM_Cmd(TIM1, ENABLE);
/* TIM1 Main Output Enable */
TIM_CtrlPWMOutputs(TIM1, ENABLE);
}
最后是串口中断函数:
//串口中断
void USART1_IRQHandler()
{
uint8_t Res;
if(USART_GetITStatus(USART1,USART_IT_RXNE)!= RESET) //检查串口1是否接收到数据
{
//USART_ITConfig(USART1, USART_IT_RXNE, DISABLE);
Res = USART_ReceiveData(USART1);
switch(Res)
{
case '1':
STM_EEPW_LEDToggle(LED1);
TimerPeriod = (SystemCoreClock / 1500 ) - 1;
PWM_Disp();
break;
case '2':
STM_EEPW_LEDToggle(LED2);
TimerPeriod = (SystemCoreClock / 2000 ) - 1;
PWM_Disp();
break;
case '3':
STM_EEPW_LEDToggle(LED3);
TimerPeriod = (SystemCoreClock / 3000 ) - 1;
PWM_Disp();
break;
case '4':
STM_EEPW_LEDToggle(LED4);
TimerPeriod = (SystemCoreClock / 4000 ) - 1;
PWM_Disp();
break;
default:
STM_EEPW_LEDToggle(LED1);
STM_EEPW_LEDToggle(LED2);
STM_EEPW_LEDToggle(LED3);
STM_EEPW_LEDToggle(LED4);
TimerPeriod = (SystemCoreClock / 1000000 ) - 1;
PWM_Disp();
break;
}
}
我还怎么理解TIM操作。这只是个试探,这两天会继续研究TIM 敬请期待。。。。
串口发送1产生1.5K方波 2->2K 3->3K 4->4K 发送其他产生1M方波
有视频,问老王要了几次,都不给验证码只好传优库了 正在审核。
操作麻烦,不好贴图片,代码贴出:
//使用TIM进行PWM输出方波
#include "stm32f10x.h"
#include "TIM.h"
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
uint16_t TimerPeriod = 0;
uint16_t Channel1Pulse = 0, Channel2Pulse = 0, Channel3Pulse = 0, Channel4Pulse = 0;
//时钟初始化
void PWM_RCCConfiguration()
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1 | RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOE|
RCC_APB2Periph_GPIOB |RCC_APB2Periph_AFIO, ENABLE);
}
//GPIO配置函数
void PWM_GPIOConfiguration()
{
GPIO_InitTypeDef GPIO_InitStructure;
/* GPIOA Configuration: Channel 1, 2 and 3 as alternate function push-pull */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_11;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* GPIOB Configuration: Channel 1N, 2N and 3N as alternate function push-pull */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
//演示函数 开启了串口对应引脚PA9PA10的AFIO时钟,就不能和串口1同时使用了。
void PWM_Disp(void)
{
PWM_RCCConfiguration();
PWM_GPIOConfiguration();
if(TimerPeriod == 0)
TimerPeriod = (SystemCoreClock / 17570 ) - 1;
Channel1Pulse = (uint16_t) (((uint32_t) 5 * (TimerPeriod - 1)) / 10);
Channel2Pulse = (uint16_t) (((uint32_t) 375 * (TimerPeriod - 1)) / 1000);
Channel3Pulse = (uint16_t) (((uint32_t) 25 * (TimerPeriod - 1)) / 100);
Channel4Pulse = (uint16_t) (((uint32_t) 125 * (TimerPeriod- 1)) / 1000);
//系统时钟预分频数 0表示不分配 1表示2分频 2表示3分配。。。。。。
TIM_TimeBaseStructure.TIM_Prescaler = 0;
//计数器模式为向上计数
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
//PWM周期
TIM_TimeBaseStructure.TIM_Period = TimerPeriod;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
//收到更新数据,用最快速度更新
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
/* Channel 1, 2,3 and 4 Configuration in PWM mode */
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;
TIM_OCInitStructure.TIM_Pulse = Channel1Pulse;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;
TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Reset;
TIM_OC1Init(TIM1, &TIM_OCInitStructure);
TIM_OCInitStructure.TIM_Pulse = Channel4Pulse;
TIM_OC4Init(TIM1, &TIM_OCInitStructure);
/* TIM1 counter enable */
TIM_Cmd(TIM1, ENABLE);
/* TIM1 Main Output Enable */
TIM_CtrlPWMOutputs(TIM1, ENABLE);
}
最后是串口中断函数:
//串口中断
void USART1_IRQHandler()
{
uint8_t Res;
if(USART_GetITStatus(USART1,USART_IT_RXNE)!= RESET) //检查串口1是否接收到数据
{
//USART_ITConfig(USART1, USART_IT_RXNE, DISABLE);
Res = USART_ReceiveData(USART1);
switch(Res)
{
case '1':
STM_EEPW_LEDToggle(LED1);
TimerPeriod = (SystemCoreClock / 1500 ) - 1;
PWM_Disp();
break;
case '2':
STM_EEPW_LEDToggle(LED2);
TimerPeriod = (SystemCoreClock / 2000 ) - 1;
PWM_Disp();
break;
case '3':
STM_EEPW_LEDToggle(LED3);
TimerPeriod = (SystemCoreClock / 3000 ) - 1;
PWM_Disp();
break;
case '4':
STM_EEPW_LEDToggle(LED4);
TimerPeriod = (SystemCoreClock / 4000 ) - 1;
PWM_Disp();
break;
default:
STM_EEPW_LEDToggle(LED1);
STM_EEPW_LEDToggle(LED2);
STM_EEPW_LEDToggle(LED3);
STM_EEPW_LEDToggle(LED4);
TimerPeriod = (SystemCoreClock / 1000000 ) - 1;
PWM_Disp();
break;
}
}
我还怎么理解TIM操作。这只是个试探,这两天会继续研究TIM 敬请期待。。。。

69楼
赚10分
一上午时间,参考野火提供的手册,成功移植uCOS
uCOS移植成功,创建了五个任务,实现两个功能。
1、4个LED以 不同频率闪烁
2、每秒串口打印数据
3、18B20没得用了,(使用定时器Tim2做精确延时,替代SysTick延时,已弄好了)
附上uCOS中添加新任务的步骤:
1、App_cfg.h中 定义任务优先级 定义任务堆栈大小
2、App.c 中 创建任务原型
3、App.h中 添加任务声明
4、main函数中 用OSTaskCreate函数创建任务。
uCOS中 的任务都是While(1) 这样的死循环,下面是我创建的几个任务:
//LED2 任务
void Task_LED2(void *p_arg)
{
//SysTick_init();
while(1)
{
STM_EEPW_LEDOn(LED2);
OSTimeDlyHMSM(0, 0,0,400);
STM_EEPW_LEDOff(LED2);
OSTimeDlyHMSM(0, 0,0,400);
}
}
。。。。。。
//串口任务。初始化18B20并打印温度
void Task_Usart(void *p_arg)
{
short temperature = 0;
//初始化DS18B20。这个功能不应该放到这里的,实验品凑合下
while(STM_EEPW_DS18B201Init(DS18B201))//初始化DS18B20,兼检测18B20
{
STM_EEPW_LEDToggle(LED1);//DS0闪烁
OSTimeDlyHMSM(0,0,0,500);
}
while(1)
{
//OS_ENTER_CRITICAL();
//printf("这里是Task_Usart任务\r\n");
temperature = DS18B201_Get_Temp(DS18B201);
printf("当前温度是:%d.%d℃ \n",temperature/10,temperature%10);
// printf();
//OS_EXIT_CRITICAL();
OSTimeDlyHMSM(0, 0,2,0);
}
}
初始化任务:
//全局任务,负责启动其他任务
void Task_Start(void *p_arg)
{
SysTick_init();
OSTaskCreate(Task_LED2,(void *)0,&task_led2_stk[TASK_LED2_STK_SIZE-1], TASK_LED2_PRIO);
OSTaskCreate(Task_LED3,(void *)0,&task_led3_stk[TASK_LED3_STK_SIZE-1], TASK_LED3_PRIO);
OSTaskCreate(Task_LED4,(void *)0,&task_led4_stk[TASK_LED3_STK_SIZE-1], TASK_LED4_PRIO);
OSTaskCreate(Task_Usart,(void *)0,&task_USART_stk[TASK_USART_STK_SIZE-1], TASK_USART_PRIO);
while(1)
{
STM_EEPW_LEDOn(LED1);
OSTimeDlyHMSM(0, 0,0,500);
STM_EEPW_LEDOff(LED1);
OSTimeDlyHMSM(0, 0,0,500);
}
}
在main函数中调用创建任务:
OSTaskCreate(Task_Start,(void *)0,&startup_task_stk[STARTUP_TASK_STK_SIZE-1], STARTUP_TASK_PRIO);
一上午时间,参考野火提供的手册,成功移植uCOS
uCOS移植成功,创建了五个任务,实现两个功能。
1、4个LED以 不同频率闪烁
2、每秒串口打印数据
3、18B20没得用了,(使用定时器Tim2做精确延时,替代SysTick延时,已弄好了)
附上uCOS中添加新任务的步骤:
1、App_cfg.h中 定义任务优先级 定义任务堆栈大小
2、App.c 中 创建任务原型
3、App.h中 添加任务声明
4、main函数中 用OSTaskCreate函数创建任务。
uCOS中 的任务都是While(1) 这样的死循环,下面是我创建的几个任务:
//LED2 任务
void Task_LED2(void *p_arg)
{
//SysTick_init();
while(1)
{
STM_EEPW_LEDOn(LED2);
OSTimeDlyHMSM(0, 0,0,400);
STM_EEPW_LEDOff(LED2);
OSTimeDlyHMSM(0, 0,0,400);
}
}
。。。。。。
//串口任务。初始化18B20并打印温度
void Task_Usart(void *p_arg)
{
short temperature = 0;
//初始化DS18B20。这个功能不应该放到这里的,实验品凑合下
while(STM_EEPW_DS18B201Init(DS18B201))//初始化DS18B20,兼检测18B20
{
STM_EEPW_LEDToggle(LED1);//DS0闪烁
OSTimeDlyHMSM(0,0,0,500);
}
while(1)
{
//OS_ENTER_CRITICAL();
//printf("这里是Task_Usart任务\r\n");
temperature = DS18B201_Get_Temp(DS18B201);
printf("当前温度是:%d.%d℃ \n",temperature/10,temperature%10);
// printf();
//OS_EXIT_CRITICAL();
OSTimeDlyHMSM(0, 0,2,0);
}
}
初始化任务:
//全局任务,负责启动其他任务
void Task_Start(void *p_arg)
{
SysTick_init();
OSTaskCreate(Task_LED2,(void *)0,&task_led2_stk[TASK_LED2_STK_SIZE-1], TASK_LED2_PRIO);
OSTaskCreate(Task_LED3,(void *)0,&task_led3_stk[TASK_LED3_STK_SIZE-1], TASK_LED3_PRIO);
OSTaskCreate(Task_LED4,(void *)0,&task_led4_stk[TASK_LED3_STK_SIZE-1], TASK_LED4_PRIO);
OSTaskCreate(Task_Usart,(void *)0,&task_USART_stk[TASK_USART_STK_SIZE-1], TASK_USART_PRIO);
while(1)
{
STM_EEPW_LEDOn(LED1);
OSTimeDlyHMSM(0, 0,0,500);
STM_EEPW_LEDOff(LED1);
OSTimeDlyHMSM(0, 0,0,500);
}
}
在main函数中调用创建任务:
OSTaskCreate(Task_Start,(void *)0,&startup_task_stk[STARTUP_TASK_STK_SIZE-1], STARTUP_TASK_PRIO);

70楼
定时器TIM2 查询方式精确定时搞定
为了配合uCOS使用,将SysTick让给了OS。现在没法使用SysTick进行延时了,只能考虑定时器了。
定时器1太过于强大,没舍得用。就定时器2吧。
使用定时器2,精确延时1ms。使用查询方式,中断方式没搞定
定时器初始化:
void Tim2DelayInit(void)
{
TIM_TimeBaseInitTypeDef timInitStruct;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
timInitStruct.TIM_Period =1; //自动装载
timInitStruct.TIM_Prescaler =72-1; //72M分频率到1000K(1M),以实现微秒级计时
timInitStruct.TIM_ClockDivision =0;
timInitStruct.TIM_CounterMode =TIM_CounterMode_Down; //向下计数
TIM_TimeBaseInit(TIM2,&timInitStruct);
}
//微秒级延时函数
void delay1us(u16 delayTime)
{
u16 TIMCounter = delayTime;
TIM_Cmd(TIM2, ENABLE);
TIM_SetCounter(TIM2, TIMCounter);
while (TIMCounter>1)
{
TIMCounter =TIM_GetCounter(TIM2);
}
TIM_Cmd(TIM2, DISABLE);
}
示波器测试delay1us(500),外加LED1口反转,能产生很精确的1K方波。跟用SysTick产生的延时一个效果,用在18B20完全没问题。
不过这个延时数不能太小了,否则次哦来的波形会受GPIO反转速度影响的。
为了配合uCOS使用,将SysTick让给了OS。现在没法使用SysTick进行延时了,只能考虑定时器了。
定时器1太过于强大,没舍得用。就定时器2吧。
使用定时器2,精确延时1ms。使用查询方式,中断方式没搞定
定时器初始化:
void Tim2DelayInit(void)
{
TIM_TimeBaseInitTypeDef timInitStruct;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
timInitStruct.TIM_Period =1; //自动装载
timInitStruct.TIM_Prescaler =72-1; //72M分频率到1000K(1M),以实现微秒级计时
timInitStruct.TIM_ClockDivision =0;
timInitStruct.TIM_CounterMode =TIM_CounterMode_Down; //向下计数
TIM_TimeBaseInit(TIM2,&timInitStruct);
}
//微秒级延时函数
void delay1us(u16 delayTime)
{
u16 TIMCounter = delayTime;
TIM_Cmd(TIM2, ENABLE);
TIM_SetCounter(TIM2, TIMCounter);
while (TIMCounter>1)
{
TIMCounter =TIM_GetCounter(TIM2);
}
TIM_Cmd(TIM2, DISABLE);
}
示波器测试delay1us(500),外加LED1口反转,能产生很精确的1K方波。跟用SysTick产生的延时一个效果,用在18B20完全没问题。
不过这个延时数不能太小了,否则次哦来的波形会受GPIO反转速度影响的。
回复
打赏帖 | |
---|---|
【我踩过的那些坑】工作那些年踩过的记忆深刻的坑被打赏10分 | |
【我踩过的那些坑】DRC使用位置错误导致的问题被打赏100分 | |
我踩过的那些坑之混合OTL功放与落地音箱被打赏50分 | |
汽车电子中巡航控制系统的使用被打赏10分 | |
【我踩过的那些坑】工作那些年踩过的记忆深刻的坑被打赏100分 | |
分享汽车电子中巡航控制系统知识被打赏10分 | |
分享安全气囊系统的检修注意事项被打赏10分 | |
分享电子控制安全气囊计算机知识点被打赏10分 | |
【分享开发笔记,赚取电动螺丝刀】【OZONE】使用方法总结被打赏20分 | |
【分享开发笔记,赚取电动螺丝刀】【S32K314】芯片启动流程分析被打赏40分 |