一、第一个问题:
因为iic通信是需要微秒级延时的,而freertos上只有毫秒级的延时。于是上网查了资料,可以用systicks的计数次数来实现us级延时(与linux驱动的定时器类似),亲测可用
//初始化函数
uint32_t DWT_Dalay_Init(void)
{
CoreDebug->DEMCR &= ~CoreDebug_DEMCR_TRCENA_Msk;
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
DWT->CTRL &= ~DWT_CTRL_CYCCNTENA_Msk;
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
DWT->CYCCNT = 0;
__ASM volatile ("NOP");
__ASM volatile ("NOP");
__ASM volatile ("NOP");
if(DWT->CYCCNT)
{
return 0;
}
else{
return 1;
}
}
//延时函数,参数是n微秒
void DWT_Delay_us(volatile uint32_t nus)
{
uint32_t clk_cycle_start = DWT->CYCCNT; // 获得当前次数
nus *= 72; // 72MHZ时,1us的时钟脉冲为72,1us计数72次,nus则是nus *= 72
while((DWT->CYCCNT - clk_cycle_start < us)); // 当计数次数达到预期时,跳出循环
}
二、第二个问题:
因为freertos是通过时间片轮转来实现多任务同时执行的,而iic的通信是毫秒级延时,所以,在iic收发数据时,要求不能进行任务调度。一开始想到的是互斥锁(信号量):
SemaphoreHandle_t Mutex;
xSemaphoreTake(Mutex, portMAX_DELAY); //获得锁
xSemaphoreGive(Mutex);//解锁
但使用后发现,互斥锁的主要功能是避免多任务同时访问临界资源,而我想实现的功能是进行iic通信时,freertos停止任务调度,因此,我使用的是任务锁,亲测有效:
vTaskSuspendAll();
iic通信代码;
if(xTaskResumeAll())
{
taskYIELD();
}