这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 电子DIY » (SD卡+FATFS,进行中)zangchao ARM DIY进程帖

共124条 13/13 |‹ 8 9 10 11 12 13 跳转至
工程师
2012-06-16 01:06:34     打赏
121楼

       STM32增强型产品,内嵌3个12位的模拟/数字转换器(ADC),每个ADC共用多达21个外部通道,可以实现单次或多次扫描转换。各通道的A/D转换可以单次、连续、扫描或间断模式执行。ADC的结果可以左对齐或右对齐方式存储在16位数据寄存器中。模拟看门狗特性允许应用程序检测输入电压是否超出用户定义的高/低阀值。
       STM32内部的温度传感器和ADCx_IN16输入通道相连接,此通道把传感器输出的电压值转换成数字值。STM内部的温度传感器支持的温度范围:-40到125摄氏度。精度较差,误差为+(-)1.5度左右。

利用STM32的内部温度传感器,可以得到芯片当前的温度。
先上图:

如图所示,有时芯片温度可以达到30℃以上,那是因为我把手压在芯片上改变温度了,哈哈。正常情况下就27℃左右。
附上内部温度传感器的配置函数代码:
/*
 * 函数名:ADC1_GPIO_Config
 * 描述  :使能ADC1和DMA1的时钟
 * 输入  :无
 * 输出  :无
 * 调用  :内部调用
 */
static void ADC1_GPIO_Config(void)        
{

 /* Enable DMA clock */
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

 /* Enable ADC1 and GPIOC clock */
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);

 }


/* 函数名:ADC1_Mode_Config
 * 描述  :配置ADC1的工作模式为MDA模式
 * 输入  : 无
 * 输出  :无
 * 调用  :内部调用
 */
static void ADC1_Mode_Config(void)
{
 DMA_InitTypeDef DMA_InitStructure;
 ADC_InitTypeDef ADC_InitStructure;

 /* DMA channel1 configuration */
    
  DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;          // 外设基地址
  DMA_InitStructure.DMA_MemoryBaseAddr = (u32)&ADC_ConvertedValue;         // AD转换值所存放的内存基地址 (就是给个地址)
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;                        // 外设作为数据传输的来源 
  DMA_InitStructure.DMA_BufferSize = 1;                                     // 定义指定DMA通道 DMA缓存的大小
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;          // 外设地址寄存器不变
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;           // 内存地址寄存器不变
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; // 数据宽度为16位
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;         // 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);           //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;     //Right
  ADC_InitStructure.ADC_NbrOfChannel = 1;                        //仅一个通道转换
  ADC_Init(ADC1, &ADC_InitStructure);

  /* ADC1 regular channel16 configuration */
  //设置采样通道IN16, 设置采样时间
  ADC_RegularChannelConfig(ADC1, ADC_Channel_16, 1, ADC_SampleTime_55Cycles5); 

  //使能温度传感器和内部参考电压  
  ADC_TempSensorVrefintCmd(ENABLE);                                   

  //ADC1->CR2|=1<<0;     //设置ADON启动
  /* 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);
}         


工程师
2012-06-16 01:40:01     打赏
122楼

       uC/OS的实时性就是靠定时中断来完成。每个时钟节拍到来,就会产生一次定时中断,中断后进行任务调度,运行就绪表中优先级最高的任务(非抢先型内核中断后继续运行被中断任务)。即过一段时间就检测是否有重要任务需要运行,是的就转而运行更重要的任务,从而确保实时性(裸机程序就无法这样做了)。
        参照野火的例程,实现了PE3,PE4和PE5 GPIO三个LED以不同频率亮灭的STM32+UCOS+LED多任务移植。
附上创建任务的代码吧,这个演示就不上图上视频了(大晚上的手机也不给力),目前正在深入研究添加更具实际应用价值的代码,以便创建自己的一套操作系统代码供以后项目使用,等有新的任务更新到时一并上图。

int main(void)
{
   BSP_Init();
 OSInit();
 OSTaskCreate(Task_Start,(void *)0,
    &startup_task_stk[STARTUP_TASK_STK_SIZE-1], STARTUP_TASK_PRIO);

 OSStart();
    return 0;
 }

void Task_Start(void *p_arg)
{
    (void)p_arg;                    // 'p_arg' 并没有用到,防止编译器提示警告
 SysTick_init();

 OSTaskCreate(Task_LED2,(void *)0,     //创建任务2
    &task_led2_stk[TASK_LED2_STK_SIZE-1], TASK_LED2_PRIO);

 OSTaskCreate(Task_LED3,(void *)0,      //创建任务3
    &task_led3_stk[TASK_LED3_STK_SIZE-1], TASK_LED3_PRIO);

    while (1)
    {
        LED1( ON );
        OSTimeDlyHMSM(0, 0,0,100);
        LED1( OFF);  
  OSTimeDlyHMSM(0, 0,0,100);    
    }
}

//任务2
void Task_LED2(void *p_arg)
{
    (void)p_arg;                 
 SysTick_init();
 
    while (1)
    {
        LED2( ON );
        OSTimeDlyHMSM(0, 0,0,200);
        LED2( OFF);
  OSTimeDlyHMSM(0, 0,0,200); 
    }
}

//任务3
void Task_LED3(void *p_arg)
{
    (void)p_arg;     
 SysTick_init();
 
    while (1)
    {
        LED3( ON );
        OSTimeDlyHMSM(0, 0,0,300);
        LED3( OFF);
  OSTimeDlyHMSM(0, 0,0,300);       
    }
}


/*
 * 函数名:BSP_Init
 * 描述  :时钟初始化、硬件初始化
 * 输入  :无
 * 输出  :无
 */
void BSP_Init(void)
{
    SystemInit();  /* 配置系统时钟为72M */ 
    LED_GPIO_Config();  /* LED 端口初始化 */
}

/*
 * 函数名:SysTick_init
 * 描述  :配置SysTick定时器
 * 输入  :无
 * 输出  :无
 */
void SysTick_init(void)
{
    SysTick_Config(SystemFrequency/OS_TICKS_PER_SEC);//初始化并使能SysTick定时器
}


工程师
2012-06-16 20:43:55     打赏
123楼

        实时时钟是一个独立的定时器。RTC模块拥有一组连续计数的计数器,在相应软件配置下,可提供时钟日历的功能。修改计数器的值可以重新设置系统当前的时间和日期。 RTC模块和时钟配置系统(RCC_BDCR寄存器)处于后备区域,即在系统复位或从待机模式唤醒后,RTC的设置和时间维持不变。 
        系统复位后,对后备寄存器和RTC的访问被禁止,这是为了防止对后备区域(BKP)的意外写操作。执行以下操作将使能对后备寄存器和RTC的访问: 
       ● 设置寄存器RCC_APB1ENR的PWREN和BKPEN位,使能电源和后备接口时钟 
       ● 设置寄存器PWR_CR的DBP位,使能对后备寄存器和RTC的访问。




附上代码
1 RTC配置代码
/* 秒中断标志,进入秒中断时置1,当时间被刷新之后清0 */
__IO uint32_t TimeDisplay; 

/*
 * 函数名:NVIC_Configuration
 * 描述  :配置RTC秒中断的主中断优先级为1,次优先级为0
 * 输入  :无
 * 输出  :无
 * 调用  :外部调用
 */
void NVIC_Configuration(void)
{
  NVIC_InitTypeDef NVIC_InitStructure;

  /* Configure one bit for preemption priority */
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);

  /* Enable the RTC Interrupt */
  NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
}

/*
 * 函数名:RTC_Configuration
 * 描述  :配置RTC
 * 输入  :无
 * 输出  :无
 * 调用  :外部调用
 */
void RTC_Configuration(void)
{
  /* Enable PWR and BKP clocks */
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);

  /* Allow access to BKP Domain */
  PWR_BackupAccessCmd(ENABLE);

  /* Reset Backup Domain */
  BKP_DeInit();

  /* Enable LSE */
  RCC_LSEConfig(RCC_LSE_ON);
  /* Wait till LSE is ready */
  while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET)
  {}

  /* Select LSE as RTC Clock Source */
  RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);

  /* Enable RTC Clock */
  RCC_RTCCLKCmd(ENABLE);

  /* Wait for RTC registers synchronization */
  RTC_WaitForSynchro();

  /* Wait until last write operation on RTC registers has finished */
  RTC_WaitForLastTask();

  /* Enable the RTC Second */
  RTC_ITConfig(RTC_IT_SEC, ENABLE);

  /* Wait until last write operation on RTC registers has finished */
  RTC_WaitForLastTask();

  /* Set RTC prescaler: set RTC period to 1sec */
  RTC_SetPrescaler(32767); /* RTC period = RTCCLK/RTC_PR = (32.768 KHz)/(32767+1) */

  /* Wait until last write operation on RTC registers has finished */
  RTC_WaitForLastTask();
}


/*
 * 函数名:Time_Regulate
 * 描述  :返回用户在超级终端中输入的时间值,并将值储存在
 *         RTC 计数寄存器中。
 * 输入  :无
 * 输出  :用户在超级终端中输入的时间值,单位为 s
 * 调用  :内部调用
 */
uint32_t Time_Regulate(void)
{
  uint32_t Tmp_HH = 0xFF, Tmp_MM = 0xFF, Tmp_SS = 0xFF;

  printf("\r\n==============时间设定=====================================");
  printf("\r\n  请设置小时");

  while (Tmp_HH == 0xFF)
  {
    Tmp_HH = USART_Scanf(23);
  }
  printf(":  %d", Tmp_HH);
  printf("\r\n  请设置分钟");
  while (Tmp_MM == 0xFF)
  {
    Tmp_MM = USART_Scanf(59);
  }
  printf(":  %d", Tmp_MM);
  printf("\r\n  请设置秒");
  while (Tmp_SS == 0xFF)
  {
    Tmp_SS = USART_Scanf(59);
  }
  printf(":  %d", Tmp_SS);

  /* Return the value to store in RTC counter register */
  return((Tmp_HH*3600 + Tmp_MM*60 + Tmp_SS));
}


/*
 * 函数名:Time_Adjust
 * 描述  :时间调节
 * 输入  :无
 * 输出  :无
 * 调用  :外部调用
 */
void Time_Adjust(void)
{
  /* Wait until last write operation on RTC registers has finished */
  RTC_WaitForLastTask();
  /* Change the current time */
  RTC_SetCounter(Time_Regulate());
  /* Wait until last write operation on RTC registers has finished */
  RTC_WaitForLastTask();
}


/*
 * 函数名:Time_Display
 * 描述  :显示当前时间值
 * 输入  :-TimeVar RTC计数值,单位为 s
 * 输出  :无
 * 调用  :内部调用
 */ 
void Time_Display(uint32_t TimeVar)
{
  uint32_t THH = 0, TMM = 0, TSS = 0;

  /* Compute  hours */
  THH = TimeVar / 3600;
  /* Compute minutes */
  TMM = (TimeVar % 3600) / 60;
  /* Compute seconds */
  TSS = (TimeVar % 3600) % 60;

  printf("\n 当前时间: %0.2d:%0.2d:%0.2d\r\n", THH, TMM, TSS);
}


/*
 * 函数名:Time_Show
 * 描述  :在超级终端中显示当前时间值
 * 输入  :无
 * 输出  :无
 * 调用  :外部调用
 */  
void Time_Show(void)
{
  printf("\n\r");

  /* Infinite loop */
  while (1)
  {
    /* If 1s has paased */
    if (TimeDisplay == 1)
    {
      /* Display current time */
      Time_Display(RTC_GetCounter());
      TimeDisplay = 0;
    }
  }
}


/*
 * 函数名:USART_Scanf
 * 描述  :串口从超级终端中获取数值
 * 输入  :- value 用户在超级终端中输入的数值
 * 输出  :无
 * 调用  :内部调用
 */
uint8_t USART_Scanf(uint32_t value)
{
  uint32_t index = 0;
  uint32_t tmp[2] = {0, 0};

  while (index < 2)
  {
    /* Loop until RXNE = 1 */
    while (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET)
    {}
    tmp[index++] = (USART_ReceiveData(USART1));
  // 从串口终端里面输进去的数是ASCII码值
    if ((tmp[index - 1] < 0x30) || (tmp[index - 1] > 0x39))
    {
      printf("\n\r请输入从0到9之间的数据");
      index--;
    }
  }
  /* Calculate the Corresponding value */
  index = (tmp[1] - 0x30) + ((tmp[0] - 0x30) * 10);
  /* Checks */
  if (index > value)
  {
    printf("\n\rPlease enter valid number between 0 and %d", value);
    return 0xFF;
  }
  return index;
}
2 USART配置代码
void USART1_printf(USART_TypeDef* USARTx, uint8_t *Data,...)
{
 const char *s;
  int d;  
  char buf[16];

  va_list ap;
  va_start(ap, Data);

 while ( *Data != 0)     // 判断是否到达字符串结束符
 {                             
  if ( *Data == 0x5c )  //'\'
  {          
   switch ( *++Data )
   {
    case 'r':                 //回车符
     USART_SendData(USARTx, 0x0d);
     Data ++;
     break;

    case 'n':                 //换行符
     USART_SendData(USARTx, 0x0a); 
     Data ++;
     break;
    
    default:
     Data ++;
        break;
   }   
  }
  else if ( *Data == '%')
  {           //
   switch ( *++Data )
   {    
    case 's':            //字符串
     s = va_arg(ap, const char *);
          for ( ; *s; s++)
     {
      USART_SendData(USARTx,*s);
      while( USART_GetFlagStatus(USARTx, USART_FLAG_TC) == RESET );
          }
     Data++;
          break;

        case 'd':          //十进制
          d = va_arg(ap, int);
          itoa(d, buf, 10);
          for (s = buf; *s; s++)
     {
      USART_SendData(USARTx,*s);
      while( USART_GetFlagStatus(USARTx, USART_FLAG_TC) == RESET );
          }
     Data++;
          break;
     default:
      Data++;
        break;
   }  
  } /* end of else if */
  else USART_SendData(USARTx, *Data++);
  while( USART_GetFlagStatus(USARTx, USART_FLAG_TC) == RESET );
 }
}


工程师
2012-06-17 20:47:19     打赏
124楼
       这次DIY收获很大啊,本科毕设时用过这个STM32做了东西,但是限于时间加上水平不够,没有搞出来,只是把硬件做出来。而这次利用这个板子最大的获益之处就是,调试了CAN和USART的协议转换,自己帮外面做了个小项目,设计了一个板子,小赚了几K,不过创造价值远不止这些,据老师说被奸商剥削太多了,哎,学生就是没有经验。
         上个自己做的板子的图片:

共124条 13/13 |‹ 8 9 10 11 12 13 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]