【沁恒微CH32V307评估板试用体验】基于CH32V307的ADC实验 - RISC-V MCU技术社区 - 电子技术william hill官网 - 广受欢迎的专业电子william hill官网 - 威廉希尔官方网站
分享 收藏 返回

[文章]

【沁恒微CH32V307评估板试用体验】基于CH32V307的ADC实验

一实验概述
利用CH32V307的12bit ADC制作一个光照强度监测与报警系统,主要的元器件有光敏电阻传感器、OLED屏幕、继电器、蜂鸣器、CH32V307开发板

二实验原理图

微信图片_20220521164032.jpg 微信图片_20220521164039.jpg
三CH32V307 ADC 外设介绍
    ADC包含两个12位ADC ,最高频率位14MHz(程序设计过程中经常采用8分频),支持18个通道其中两个位内部信号源,可以实现单次转换、连续转换,通道间自动扫描模式、间断模式、外部触发模式、双重采样等功能。

   这里我们主要采用ADC1的通道1,实现外部光照强度大小的测量,并在OLED模块上显示,以及设计最大报警阈值,通过继电器控制蜂鸣器。四代码实现ADC.c
  1. #include "adc.h"

  2. s16 Calibrattion_Val = 0;//校准值
  3. void MX_ADC_Init(void)
  4. {
  5.     ADC_InitTypeDef hadc1;//ADC 句柄
  6.     GPIO_InitTypeDef GPIO_Initure;//GPIO 句柄

  7.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1|RCC_APB2Periph_GPIOA, ENABLE);
  8.     //开启ADC1 GPIOA的时钟
  9.     RCC_ADCCLKConfig(RCC_PCLK2_Div8);//ADC 频率设置

  10.     GPIO_Initure.GPIO_Pin=GPIO_Pin_0;
  11.     GPIO_Initure.GPIO_Mode=GPIO_Mode_AIN;//选择模拟输入
  12.     GPIO_Init(GPIOA, &GPIO_Initure);


  13.     hadc1.ADC_Mode=ADC_Mode_Independent;//配置ADC位独立模式
  14.     hadc1.ADC_ScanConvMode=DISABLE;//不选择扫描模式
  15.     hadc1.ADC_ContinuousConvMode=ENABLE;//使能连续转换模式
  16.     hadc1.ADC_DataAlign=ADC_DataAlign_Right;
  17.     hadc1.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;
  18.     hadc1.ADC_NbrOfChannel=1;
  19.     ADC_Init(ADC1, &hadc1);

  20.     ADC_Cmd(ADC1, ENABLE);

  21.     ADC_BufferCmd(ADC1, DISABLE);                               //disable buffer
  22.          //测量ADC校准数据,也可以不使用。
  23.          ADC_ResetCalibration(ADC1);
  24.          while(ADC_GetResetCalibrationStatus(ADC1));
  25.          ADC_StartCalibration(ADC1);
  26.          while(ADC_GetCalibrationStatus(ADC1));
  27.          Calibrattion_Val = Get_CalibrationValue(ADC1);

  28.          ADC_BufferCmd(ADC1, ENABLE);                                //enable buffer


  29. }




  30. u16 Get_ADC_Val(u8 ch)
  31. {
  32.    u16 val;

  33.    ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_239Cycles5 );
  34.    ADC_SoftwareStartConvCmd(ADC1, ENABLE);

  35.    while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));
  36.    val = ADC_GetConversionValue(ADC1);

  37.    return val;
  38. }

OLED.c 这里我们常采用软件SPI实现屏幕显示
  1. #include "oled.h"
  2. #include "oledfont.h"

  3. u8 OLED_GRAM[144][8];

  4. //反显函数
  5. void OLED_ColorTurn(u8 i)
  6. {
  7.     if(i==0)
  8.         {
  9.             OLED_WR_Byte(0xA6,OLED_CMD);//正常显示
  10.         }
  11.     if(i==1)
  12.         {
  13.             OLED_WR_Byte(0xA7,OLED_CMD);//反色显示
  14.         }
  15. }

  16. //屏幕旋转180度
  17. void OLED_DisplayTurn(u8 i)
  18. {
  19.     if(i==0)
  20.         {
  21.             OLED_WR_Byte(0xC8,OLED_CMD);//正常显示
  22.             OLED_WR_Byte(0xA1,OLED_CMD);
  23.         }
  24.     if(i==1)
  25.         {
  26.             OLED_WR_Byte(0xC0,OLED_CMD);//反转显示
  27.             OLED_WR_Byte(0xA0,OLED_CMD);
  28.         }
  29. }


  30. void OLED_WR_Byte(u8 dat,u8 cmd)
  31. {
  32.     u8 i;
  33.     if(cmd)
  34.       OLED_DC_Set();
  35.     else
  36.       OLED_DC_Clr();
  37.     OLED_CS_Clr();
  38.     for(i=0;i<8;i++)
  39.     {
  40.         OLED_SCLK_Clr();
  41.         if(dat&0x80)
  42.            OLED_SDIN_Set();
  43.         else
  44.            OLED_SDIN_Clr();
  45.         OLED_SCLK_Set();
  46.         dat<<=1;
  47.     }
  48.     OLED_CS_Set();
  49.     OLED_DC_Set();
  50. }

  51. //开启OLED显示
  52. void OLED_DisPlay_On(void)
  53. {
  54.     OLED_WR_Byte(0x8D,OLED_CMD);//电荷泵使能
  55.     OLED_WR_Byte(0x14,OLED_CMD);//开启电荷泵
  56.     OLED_WR_Byte(0xAF,OLED_CMD);//点亮屏幕
  57. }

  58. //关闭OLED显示
  59. void OLED_DisPlay_Off(void)
  60. {
  61.     OLED_WR_Byte(0x8D,OLED_CMD);//电荷泵使能
  62.     OLED_WR_Byte(0x10,OLED_CMD);//关闭电荷泵
  63.     OLED_WR_Byte(0xAF,OLED_CMD);//关闭屏幕
  64. }

  65. //更新显存到OLED
  66. void OLED_Refresh(void)
  67. {
  68.     u8 i,n;
  69.     for(i=0;i<8;i++)
  70.     {
  71.        OLED_WR_Byte(0xb0+i,OLED_CMD); //设置行起始地址
  72.        OLED_WR_Byte(0x00,OLED_CMD);   //设置低列起始地址
  73.        OLED_WR_Byte(0x10,OLED_CMD);   //设置高列起始地址
  74.        for(n=0;n<128;n++)
  75.          OLED_WR_Byte(OLED_GRAM[n][i],OLED_DATA);
  76.   }
  77. }
  78. //清屏函数
  79. void OLED_Clear(void)
  80. {
  81.     u8 i,n;
  82.     for(i=0;i<8;i++)
  83.     {
  84.        for(n=0;n<128;n++)
  85.             {
  86.              OLED_GRAM[n][i]=0;//清除所有数据
  87.             }
  88.   }
  89.     OLED_Refresh();//更新显示
  90. }

  91. //画点
  92. //x:0~127
  93. //y:0~63
  94. void OLED_DrawPoint(u8 x,u8 y)
  95. {
  96.     u8 i,m,n;
  97.     i=y/8;
  98.     m=y%8;
  99.     n=1<
  100.     OLED_GRAM[x][i]|=n;
  101. }

  102. //清除一个点
  103. //x:0~127
  104. //y:0~63
  105. void OLED_ClearPoint(u8 x,u8 y)
  106. {
  107.     u8 i,m,n;
  108.     i=y/8;
  109.     m=y%8;
  110.     n=1<
  111.     OLED_GRAM[x][i]=~OLED_GRAM[x][i];
  112.     OLED_GRAM[x][i]|=n;
  113.     OLED_GRAM[x][i]=~OLED_GRAM[x][i];
  114. }


  115. //画线
  116. //x:0~128
  117. //y:0~64
  118. void OLED_DrawLine(u8 x1,u8 y1,u8 x2,u8 y2)
  119. {
  120.     u8 i,k,k1,k2;
  121.     if((x1<0)||(x2>128)||(y1<0)||(y2>64)||(x1>x2)||(y1>y2))return;
  122.     if(x1==x2)    //画竖线
  123.     {
  124.             for(i=0;i<(y2-y1);i++)
  125.             {
  126.                 OLED_DrawPoint(x1,y1+i);
  127.             }
  128.   }
  129.     else if(y1==y2)   //画横线
  130.     {
  131.             for(i=0;i<(x2-x1);i++)
  132.             {
  133.                 OLED_DrawPoint(x1+i,y1);
  134.             }
  135.   }
  136.     else      //画斜线
  137.     {
  138.         k1=y2-y1;
  139.         k2=x2-x1;
  140.         k=k1*10/k2;
  141.         for(i=0;i<(x2-x1);i++)
  142.             {
  143.               OLED_DrawPoint(x1+i,y1+i*k/10);
  144.             }
  145.     }
  146. }
  147. //x,y:圆心坐标
  148. //r:圆的半径
  149. void OLED_DrawCircle(u8 x,u8 y,u8 r)
  150. {
  151.     int a, b,num;
  152.     a = 0;
  153.     b = r;
  154.     while(2 * b * b >= r * r)
  155.     {
  156.         OLED_DrawPoint(x + a, y - b);
  157.         OLED_DrawPoint(x - a, y - b);
  158.         OLED_DrawPoint(x - a, y + b);
  159.         OLED_DrawPoint(x + a, y + b);

  160.         OLED_DrawPoint(x + b, y + a);
  161.         OLED_DrawPoint(x + b, y - a);
  162.         OLED_DrawPoint(x - b, y - a);
  163.         OLED_DrawPoint(x - b, y + a);

  164.         a++;
  165.         num = (a * a + b * b) - r*r;//计算画的点离圆心的距离
  166.         if(num > 0)
  167.         {
  168.             b--;
  169.             a--;
  170.         }
  171.     }
  172. }



  173. //在指定位置显示一个字符,包括部分字符
  174. //x:0~127
  175. //y:0~63
  176. //size:选择字体 12/16/24
  177. //取模方式 逐列式
  178. void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 size1)
  179. {
  180.     u8 i,m,temp,size2,chr1;
  181.     u8 y0=y;
  182.     size2=(size1/8+((size1%8)?1:0))*(size1/2);  //得到字体一个字符对应点阵集所占的字节数
  183.     chr1=chr-' ';  //计算偏移后的值
  184.     for(i=0;i
  185.     {
  186.         if(size1==12)
  187.         {temp=asc2_1206[chr1][i];} //调用1206字体
  188.         else if(size1==16)
  189.         {temp=asc2_1608[chr1][i];} //调用1608字体
  190.         else if(size1==24)
  191.         {temp=asc2_2412[chr1][i];} //调用2412字体
  192.         else return;
  193.                 for(m=0;m<8;m++)           //写入数据
  194.                 {
  195.                     if(temp&0x80)OLED_DrawPoint(x,y);
  196.                     else OLED_ClearPoint(x,y);
  197.                     temp<<=1;
  198.                     y++;
  199.                     if((y-y0)==size1)
  200.                     {
  201.                         y=y0;
  202.                         x++;
  203.                         break;
  204.           }
  205.                 }
  206.   }
  207. }


  208. //显示字符串
  209. //x,y:起点坐标
  210. //size1:字体大小
  211. //*chr:字符串起始地址
  212. void OLED_ShowString(u8 x,u8 y,u8 *chr,u8 size1)
  213. {
  214.     while((*chr>=' ')&&(*chr<='~'))//判断是不是非法字符!
  215.     {
  216.         OLED_ShowChar(x,y,*chr,size1);
  217.         x+=size1/2;
  218.         if(x>128-size1)  //换行
  219.         {
  220.             x=0;
  221.             y+=2;
  222.     }
  223.         chr++;
  224.   }
  225. }

  226. //m^n
  227. u32 OLED_Pow(u8 m,u8 n)
  228. {
  229.     u32 result=1;
  230.     while(n--)
  231.     {
  232.       result*=m;
  233.     }
  234.     return result;
  235. }

  236. ////显示2个数字
  237. ////x,y :起点坐标
  238. ////len :数字的位数
  239. ////size:字体大小
  240. void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 size1)
  241. {
  242.     u8 t,temp;
  243.     for(t=0;t
  244.     {
  245.         temp=(num/OLED_Pow(10,len-t-1))%10;
  246.             if(temp==0)
  247.             {
  248.                 OLED_ShowChar(x+(size1/2)*t,y,'0',size1);
  249.       }
  250.             else
  251.             {
  252.               OLED_ShowChar(x+(size1/2)*t,y,temp+'0',size1);
  253.             }
  254.   }
  255. }

  256. //显示汉字
  257. //x,y:起点坐标
  258. //num:汉字对应的序号
  259. //取模方式 列行式
  260. void OLED_ShowChinese(u8 x,u8 y,u8 num,u8 size1)
  261. {
  262.     u8 i,m,n=0,temp,chr1;
  263.     u8 x0=x,y0=y;
  264.     u8 size3=size1/8;
  265.     while(size3--)
  266.     {
  267.         chr1=num*size1/8+n;
  268.         n++;
  269.             for(i=0;i
  270.             {
  271.                 if(size1==16)
  272.                         {temp=Hzk1[chr1][i];}//调用16*16字体
  273.                 else if(size1==24)
  274.                         {temp=Hzk2[chr1][i];}//调用24*24字体
  275.                 else if(size1==32)
  276.                         {temp=Hzk3[chr1][i];}//调用32*32字体
  277.                 else if(size1==64)
  278.                         {temp=Hzk4[chr1][i];}//调用64*64字体
  279.                 else return;

  280.                         for(m=0;m<8;m++)
  281.                             {
  282.                                 if(temp&0x01)OLED_DrawPoint(x,y);
  283.                                 else OLED_ClearPoint(x,y);
  284.                                 temp>>=1;
  285.                                 y++;
  286.                             }
  287.                             x++;
  288.                             if((x-x0)==size1)
  289.                             {x=x0;y0=y0+8;}
  290.                             y=y0;
  291.              }
  292.     }
  293. }

  294. //num 显示汉字的个数
  295. //space 每一遍显示的间隔
  296. void OLED_ScrollDisplay(u8 num,u8 space)
  297. {
  298.     u8 i,n,t=0,m=0,r;
  299.     while(1)
  300.     {
  301.         if(m==0)
  302.         {
  303.         OLED_ShowChinese(128,24,t,16); //写入一个汉字保存在OLED_GRAM[][]数组中
  304.             t++;
  305.         }
  306.         if(t==num)
  307.             {
  308.                 for(r=0;r<16*space;r++)      //显示间隔
  309.                  {
  310.                     for(i=0;i<144;i++)
  311.                         {
  312.                             for(n=0;n<8;n++)
  313.                             {
  314.                                 OLED_GRAM[i-1][n]=OLED_GRAM[i][n];
  315.                             }
  316.                         }
  317.            OLED_Refresh();
  318.                  }
  319.         t=0;
  320.       }
  321.         m++;
  322.         if(m==16){m=0;}
  323.         for(i=0;i<144;i++)   //实现左移
  324.         {
  325.             for(n=0;n<8;n++)
  326.             {
  327.                 OLED_GRAM[i-1][n]=OLED_GRAM[i][n];
  328.             }
  329.         }
  330.         OLED_Refresh();
  331.     }
  332. }

  333. //配置写入数据的起始位置
  334. void OLED_WR_BP(u8 x,u8 y)
  335. {
  336.     OLED_WR_Byte(0xb0+y,OLED_CMD);//设置行起始地址
  337.     OLED_WR_Byte(((x&0xf0)>>4)|0x10,OLED_CMD);
  338.     OLED_WR_Byte((x&0x0f),OLED_CMD);
  339. }

  340. //x0,y0:起点坐标
  341. //x1,y1:终点坐标
  342. //BMP[]:要写入的图片数组
  343. void OLED_ShowPicture(u8 x0,u8 y0,u8 x1,u8 y1,u8 BMP[])
  344. {
  345.     u32 j=0;
  346.     u8 x=0,y=0;
  347.     if(y%8==0)y=0;
  348.     else y+=1;
  349.     for(y=y0;y
  350.      {
  351.          OLED_WR_BP(x0,y);
  352.          for(x=x0;x
  353.          {
  354.              OLED_WR_Byte(BMP[j],OLED_DATA);
  355.              j++;
  356.      }
  357.      }
  358. }
  359. //OLED的初始化
  360. void OLED_Init(void)
  361. {
  362.     GPIO_InitTypeDef  GPIO_InitStructure;

  363.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);    //使能A端口时钟
  364.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5;
  365.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;         //推挽输出
  366.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//速度50MHz
  367.     GPIO_Init(GPIOA, &GPIO_InitStructure);
  368.     GPIO_SetBits(GPIOA,GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5);

  369.     OLED_RST_Clr();//复位
  370.     Delay_Ms(20);
  371.     OLED_RST_Set();

  372.     OLED_WR_Byte(0xAE,OLED_CMD);//--turn off oled panel
  373.     OLED_WR_Byte(0x00,OLED_CMD);//---set low column address
  374.     OLED_WR_Byte(0x10,OLED_CMD);//---set high column address
  375.     OLED_WR_Byte(0x40,OLED_CMD);//--set start line address  Set Mapping RAM Display Start Line (0x00~0x3F)
  376.     OLED_WR_Byte(0x81,OLED_CMD);//--set contrast control register
  377.     OLED_WR_Byte(0xCF,OLED_CMD);// Set SEG Output Current Brightness
  378.     OLED_WR_Byte(0xA1,OLED_CMD);//--Set SEG/Column Mapping     0xa0左右反置 0xa1正常
  379.     OLED_WR_Byte(0xC8,OLED_CMD);//Set COM/Row Scan Direction   0xc0上下反置 0xc8正常
  380.     OLED_WR_Byte(0xA6,OLED_CMD);//--set normal display
  381.     OLED_WR_Byte(0xA8,OLED_CMD);//--set multiplex ratio(1 to 64)
  382.     OLED_WR_Byte(0x3f,OLED_CMD);//--1/64 duty
  383.     OLED_WR_Byte(0xD3,OLED_CMD);//-set display offset   Shift Mapping RAM Counter (0x00~0x3F)
  384.     OLED_WR_Byte(0x00,OLED_CMD);//-not offset
  385.     OLED_WR_Byte(0xd5,OLED_CMD);//--set display clock divide ratio/oscillator frequency
  386.     OLED_WR_Byte(0x80,OLED_CMD);//--set divide ratio, Set Clock as 100 Frames/Sec
  387.     OLED_WR_Byte(0xD9,OLED_CMD);//--set pre-charge period
  388.     OLED_WR_Byte(0xF1,OLED_CMD);//Set Pre-Charge as 15 Clocks & Discharge as 1 Clock
  389.     OLED_WR_Byte(0xDA,OLED_CMD);//--set com pins hardware configuration
  390.     OLED_WR_Byte(0x12,OLED_CMD);
  391.     OLED_WR_Byte(0xDB,OLED_CMD);//--set vcomh
  392.     OLED_WR_Byte(0x40,OLED_CMD);//Set VCOM Deselect Level
  393.     OLED_WR_Byte(0x20,OLED_CMD);//-Set Page Addressing Mode (0x00/0x01/0x02)
  394.     OLED_WR_Byte(0x02,OLED_CMD);//
  395.     OLED_WR_Byte(0x8D,OLED_CMD);//--set Charge Pump enable/disable
  396.     OLED_WR_Byte(0x14,OLED_CMD);//--set(0x10) disable
  397.     OLED_WR_Byte(0xA4,OLED_CMD);// Disable Entire Display On (0xa4/0xa5)
  398.     OLED_WR_Byte(0xA6,OLED_CMD);// Disable Inverse Display On (0xa6/a7)
  399.     OLED_WR_Byte(0xAF,OLED_CMD);
  400.     OLED_Clear();
  401. }

main.c
  1. #include "debug.h"
  2. #include "gpio.h"
  3. #include "oled.h"
  4. #include "adc.h"
  5. /* Global typedef */
  6. char tjcstr[80];
  7. uint16_t adc_value;
  8. /* Global define */

  9. /* Global Variable */


  10. /*********************************************************************
  11. * @fn      main
  12. *
  13. * [url=home.php?mod=space&uid=2666770]@Brief[/url]   Main program.
  14. *
  15. * [url=home.php?mod=space&uid=1141835]@Return[/url]  none
  16. */
  17. int main(void)
  18. {
  19.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  20.         Delay_Init();
  21.         USART_Printf_Init(115200);
  22.         printf("SystemClk:%drn",SystemCoreClock);
  23.         printf("This is printf examplern");
  24.         MX_GPIO_Init();
  25.     OLED_Init();
  26.     OLED_ColorTurn(0);//0正常显示,1 反色显示
  27.     OLED_DisplayTurn(0);//0正常显示 1 屏幕翻转显示
  28.     OLED_Refresh();
  29.     MX_ADC_Init();
  30.         while(1)
  31.     {

  32.             adc_value=4096-Get_ADC_Val(ADC_Channel_0);
  33.             sprintf(tjcstr,"%d",adc_value);
  34.             OLED_ShowString(12,8,(u8 *)"ADC",24);
  35.             OLED_ShowString(36,32,(u8 *)tjcstr,24);
  36.             Delay_Ms(200);
  37.             OLED_Refresh();
  38.             GPIO_SetBits(GPIOD, GPIO_Pin_10);
  39.             if(adc_value>=3000)
  40.             {
  41.                 GPIO_SetBits(GPIOD, GPIO_Pin_10);
  42.                 Delay_Ms(50);
  43.                 GPIO_ResetBits(GPIOD, GPIO_Pin_10);
  44.                 Delay_Ms(50);
  45.             }

  46.         }
  47. }
实现效果
[media]https://yingsheng.elecfans.com/share/user/video/1Oz7sDYGrioS1nLP3gA2nQ[/media]
[media]https://yingsheng.elecfans.com/share/user/video/eDUXcsSn5vzn3O%2FMn4OywA[/media]
源代码

更多回帖

×
发帖